Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Other versions, such as Ruby 1.9, Ruby 2.x, and JRuby, are compatible with [lega

### Bundler
```ruby
gem 'serpapi', '~> 1.0', '>= 1.0.1'
gem 'serpapi', '~> 1.0', '>= 1.0.2'
```

### Gem
Expand Down Expand Up @@ -1085,6 +1085,7 @@ Ruby versions validated by Github Actions:
* doc: [Github Actions.](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml)

## Change logs
* [2025-11-17] 1.0.2 Implement `to_s` and `inspect` functions for client
* [2025-07-18] 1.0.1 Add support for old Ruby versions (2.7, 3.0)
* [2025-07-01] 1.0.0 Full API support

Expand Down
3 changes: 2 additions & 1 deletion README.md.erb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Other versions, such as Ruby 1.9, Ruby 2.x, and JRuby, are compatible with [lega

### Bundler
```ruby
gem 'serpapi', '~> 1.0', '>= 1.0.1'
gem 'serpapi', '~> 1.0', '>= 1.0.2'
```

### Gem
Expand Down Expand Up @@ -566,6 +566,7 @@ Ruby versions validated by Github Actions:
* doc: [Github Actions.](https://github.com/serpapi/serpapi-ruby/actions/workflows/ci.yml)

## Change logs
* [2025-11-17] 1.0.2 Implement `to_s` and `inspect` functions for client
* [2025-07-18] 1.0.1 Add support for old Ruby versions (2.7, 3.0)
* [2025-07-01] 1.0.0 Full API support

Expand Down
14 changes: 14 additions & 0 deletions lib/serpapi/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,20 @@ def close
@socket.close if @socket
end

def to_s
# If the api_key is set, mask it
masked_api_key = if api_key && api_key.length > 4
"#{api_key[0..3]}#{'*' * (api_key.length - 4)}"
else
api_key
end
"SerpApi::Client(engine: #{engine}, api_key: #{masked_api_key}, persistent: #{persistent?}, timeout: #{timeout}s)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Ron, that's a good idea.

It's usually best to follow the conventions of popular gems when overriding such an ubiquitous method as inspect. It's always worthwhile looking at the Rails source code, for example. bundle open activerecord and then search for def inspect yields some examples.

Most gems preserve the #<....> formatting, for example.

It's also helpful to show both the leading and trailing characters of the masked key for easier comparison with a known value.

How about something like this?

    def inspect
      masked_key = api_key && (api_key.length > 4 ? "#{api_key[..1]}****#{api_key[-2..]}" : '****')
      "#<#{self.class} @engine=#{engine} @timeout=#{timeout} @persistent=#{persistent} api_key=#{masked_key}>"
    end

Result:

CleanShot 2025-11-18 at 11 25 57@2x

And I'd leave to_s alone.

end

def inspect
to_s
end

private

# @param [Hash] params to merge with default parameters provided to the constructor.
Expand Down
2 changes: 1 addition & 1 deletion lib/serpapi/version.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module SerpApi
# Current version of the gem
VERSION = '1.0.1'.freeze
VERSION = '1.0.2'.freeze
end
21 changes: 20 additions & 1 deletion spec/serpapi/client/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,25 @@
raise("wrong exception: #{e}")
end
end

it 'should not expose api_key in to_s and inspect' do
str = client.to_s
expect(str).to include('SerpApi::Client(engine: google, api_key: ')
expect(str).to_not include(ENV['SERPAPI_KEY'])

inspect_str = client.inspect
expect(inspect_str).to include('SerpApi::Client(engine: google, api_key: ')
expect(inspect_str).to_not include(ENV['SERPAPI_KEY'])
end

it 'should gracefully handle api_key values shorter than 5 characters' do
short_key_client = SerpApi::Client.new(engine: 'google', api_key: 'abcd', timeout: 10)
str = short_key_client.to_s
expect(str).to include('SerpApi::Client(engine: google, api_key: abcd')

inspect_str = short_key_client.inspect
expect(inspect_str).to include('SerpApi::Client(engine: google, api_key: abcd')
end
end

describe 'SerpApi client with persitency enable' do
Expand Down Expand Up @@ -136,4 +155,4 @@
expect(client.socket).to be_nil
expect(client.close).to be_nil
end
end
end
Loading