someapi 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f026e9cad3240ec1c275409e82272d601ca13230
4
- data.tar.gz: e73c051d5f2eba1c9f10e90cc948365be6d9c05b
3
+ metadata.gz: 789f481193c3ec05d0199300a2ccf08fe882fd34
4
+ data.tar.gz: 43bcf8ffc6ae3ce950023f8d2efcd1341020fec4
5
5
  SHA512:
6
- metadata.gz: c64f30f3523c35d6604c939553a321faab0fc8b05f45c00ddd7fea0d8201a01c263a48186bc54dfec9f9d561c177e9ec22513bb47f030b2b96b7c5ee99b9854b
7
- data.tar.gz: f97a01af2f90419dbe770d16e0e14c2ed75309e4717cc0d1751007e93d68111fbb35cb81b3c7494dd26f0fc14f928a206940b7113b6070a32c79a0c377fdf7c2
6
+ metadata.gz: cf2e8df6edf80e54a8d2d4bcc90661d2600a991ca9ec2fd917aaedd3b0ecfc42a076927edf90a6e70a048d83ed78b16cf75a01fd6573faf849c246e974a3c9ca
7
+ data.tar.gz: 1cd1cfe77ce345c08edb8a7c8317be9a8adad1da9fe73211909d61996c171ae4540fae50a1de8a42f19e0c70d1f02c22b24437f8901d3d2bb7a399a34333ace9
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format documentation
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.2
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - "2.1.2"
5
+ - "2.0.0"
6
+ - "1.9.3"
7
+ script: bundle exec rspec spec
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # SomeAPI
2
+ [![Build Status](https://travis-ci.org/jellymann/someapi.svg?branch=master)](https://travis-ci.org/jellymann/someapi)
3
+ [![Code Climate](https://codeclimate.com/github/jellymann/someapi.png)](https://codeclimate.com/github/jellymann/someapi)
2
4
 
3
5
  Built around HTTParty, SomeAPI provides a generic wrapper for your favourite RESTful WebAPI. Simply extend Some::API and apply your usual HTTParty options like base_uri, then call your new API and party harder!
4
6
 
5
- ## Installation
7
+ ## Get Some
6
8
 
7
9
  Add this line to your application's Gemfile:
8
10
 
@@ -48,6 +50,10 @@ Don't stub your toe on external services!
48
50
 
49
51
  Some::API.include WebMock::API
50
52
 
53
+ NOTE: If you're using Ruby version before 2.1.x, then you'll have to include WebMock like this:
54
+
55
+ Some::API.send :include, WebMock::API
56
+
51
57
  3. Adding `stub` before the HTTP method in a SomeAPI request will instead return a Webmock stub after the bang.
52
58
 
53
59
  github = Github.new
@@ -59,13 +65,13 @@ Stubs look exactly the same as their corresponding requests except for the prese
59
65
 
60
66
  ## Tips and Gotchas
61
67
 
62
- If your request ends in a `[someth]` remember to put a dot before the bang, as in the examples. Ruby doesn't define the (very odd and mostly useless actually) operator for `[]!`.
68
+ If your request ends in a `[whatever]` remember to put a dot before the bang, as in the examples. Ruby doesn't define the (very odd and mostly useless actually) operator for `[]!`.
63
69
 
64
70
  Posting hashes can be done more succinctly by using the `<<` operator, as follows (using the post example from above):
65
71
 
66
72
  github.post.repos[@username][@repo].pulls << { title: "Foo", body: "Pull my Foo", ... }
67
73
 
68
- Also note that every time you do this (put the bang at the beginning of a request):
74
+ CAUTION: Every time you do the following (ie. put the bang at the beginning of a request):
69
75
 
70
76
  !github.get.users[@some_user]
71
77
 
data/lib/someapi.rb CHANGED
@@ -9,23 +9,26 @@ module Some
9
9
 
10
10
  API_REGEX = /^[a-zA-Z0-9_]+[!]?$/
11
11
 
12
- def initialize options={}, meth=nil, path=nil, stubbed=false
13
- @meth = meth
14
- @path = path
15
- @options = options
12
+ def initialize options={}
13
+ @method = options[:method]
14
+ @path = options[:path]
16
15
 
17
16
  # stubbed is a flag set when you're stubbing the API call
18
17
  # used in testing
19
18
  # just call 'stub' in the call chain before the http_method method
20
- @stubbed = stubbed
19
+ @stubbed = options[:stubbed]
20
+
21
+ @options = options.delete_if do |k|
22
+ [:method, :path, :stubbed].include? k
23
+ end
21
24
  end
22
25
 
23
26
  # http_method methods
24
27
  # used in the call chain to set the http method
25
28
  %W(get post put patch delete copy move head options).each do |meth|
26
29
  define_method(meth) do
27
- unless @meth
28
- self.class.new Hash.new, meth.to_s, nil, @stubbed
30
+ unless @method
31
+ make_new method: meth.to_s, stubbed: @stubbed
29
32
  else
30
33
  self[meth]
31
34
  end
@@ -35,8 +38,8 @@ module Some
35
38
  # use in the call chain to flag this request as a stub
36
39
  # used in testing for setting up API-call stubs
37
40
  def stub
38
- unless @meth
39
- self.class.new Hash.new, @meth, @path, true
41
+ unless @method
42
+ make_new method: @method, path: @path, stubbed: true
40
43
  else
41
44
  self['stub']
42
45
  end
@@ -57,77 +60,69 @@ module Some
57
60
  # 'calls' the API request
58
61
  # (or makes the stub, if stubbed)
59
62
  def ! options = {}
63
+ merged_options = merge_headers_and_queries options
60
64
  unless @stubbed
61
- self.class.send(@meth, @path || '/', deep_merge(options,@options))
65
+ self.class.send(@method, @path || '/', merged_options)
62
66
  else
63
67
  uri = "#{self.class.base_uri}#{@path}"
64
68
 
65
- deep_merge(options,@options)
66
- process_headers(options)
67
- process_query(options)
68
- options = self.class.default_options.
69
- merge(@options.merge(options))
70
-
71
- stub_request(@meth.to_sym, uri.to_s).with(options)
69
+ stub_request(@method.to_sym, uri.to_s).with merged_options
72
70
  end
73
71
  end
74
72
 
75
73
  # chains 'thing' onto URL path
76
74
  def [] thing
77
- self.class.new @options, @meth, "#{@path || ''}/#{thing}", @stubbed
75
+ make_new method: @method,
76
+ path: "#{@path || ''}/#{thing}",
77
+ stubbed: @stubbed
78
78
  end
79
79
 
80
80
  # this is where the fun begins...
81
81
  def method_missing meth, *args, &block
82
- meths = meth.to_s
83
- if @meth && meths =~ API_REGEX
82
+ meth_s = meth.to_s
83
+ if @method && meth_s =~ API_REGEX
84
84
 
85
- if meths.end_with?('!')
85
+ if meth_s.end_with?('!')
86
86
  # `foo! bar' is syntactic sugar for `foo.! bar'
87
- self[meths[0...-1]].!(args[0] || {})
87
+ self[meth_s[0...-1]].!(args[0] || {})
88
88
 
89
89
  else
90
90
  # chain the method name onto URL path
91
- self[meths]
91
+ self[meth_s]
92
92
  end
93
93
  else
94
94
  super
95
95
  end
96
96
  end
97
97
 
98
- def respond_to_missing? meth
99
- @meth && meth.to_s =~ API_REGEX
98
+ def respond_to_missing? method
99
+ @method && method.to_s =~ API_REGEX
100
100
  end
101
101
 
102
102
  private
103
103
 
104
- # shamelessly stolen from HTTParty
105
- def process_headers(options)
106
- if options[:headers] && self.class.headers.any?
107
- options[:headers] = self.class.headers.merge(options[:headers])
108
- end
104
+ def merge_headers_and_queries options
105
+ merge_headers merge_queries options
109
106
  end
110
107
 
111
- # shamelessly copied from above, but for :query
112
- def process_query(options)
113
- if self.class.default_options[:default_params]
114
- options[:query] = self.class.default_options[:default_params].
115
- merge(options[:query] || {})
116
- end
108
+ def merge_headers options
109
+ options.merge({
110
+ headers: (self.class.headers || {}).
111
+ merge((@options[:headers] || {}).
112
+ merge(options[:headers] || {}))
113
+ })
117
114
  end
118
115
 
119
- # merge a hash within a hash from two hashes (yo-dawg...)
120
- def merge_stuff(a,b,tag)
121
- if a[tag] && b[tag]
122
- a[tag] = b[tag].merge(a[tag])
123
- end
116
+ def merge_queries options
117
+ options.merge({
118
+ query: (self.class.default_options[:default_params] || {}).
119
+ merge((@options[:query] || {}).
120
+ merge(options[:query]|| {}))
121
+ })
124
122
  end
125
123
 
126
- # just merge_stuff like :headers and :query... you know, HTTP stuff
127
- def deep_merge(a,b)
128
- merge_stuff(a,b,:headers)
129
- merge_stuff(a,b,:query)
130
- b.merge(a)
124
+ def make_new opts={}
125
+ self.class.new @options.merge(opts)
131
126
  end
132
127
 
133
128
  end
@@ -1,3 +1,3 @@
1
1
  module Some
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/someapi.gemspec CHANGED
@@ -18,8 +18,12 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_runtime_dependency "httparty", "~> 0.13.1"
21
+ spec.required_ruby_version = ">= 1.9.3"
22
+
23
+ spec.add_runtime_dependency "httparty", "~> 0.13"
22
24
 
23
25
  spec.add_development_dependency "bundler", "~> 1.6"
24
- spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rake", "~> 10.3"
27
+ spec.add_development_dependency "rspec", '~> 3.0'
28
+ spec.add_development_dependency "webmock", '~> 1.18'
25
29
  end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe Some::API do
4
+
5
+ let(:moar_headers) { { 'X-Fizz' => 'Buzz' } }
6
+ let(:moar_params) { { 'fizz' => 'buzz' } }
7
+ let(:all_the_headers) { test_headers.merge(moar_headers) }
8
+ let(:all_the_params) { test_params.merge(moar_params) }
9
+ let(:test_body) { { 'baz' => 'qux' } }
10
+
11
+ let(:even_moar_headers) { { 'X-Baz' => 'Qux' } }
12
+ let(:even_moar_params) { { 'baz' => 'qux' } }
13
+
14
+ let(:api) { TestAPI.new query: moar_params,
15
+ headers: moar_headers }
16
+
17
+ it 'requests endpoints using method_missing' do
18
+ stub = stub_request(:get, "http://example.com/foo/bar?fizz=buzz&foo=bar").
19
+ with(:headers => all_the_headers)
20
+
21
+ api.get.foo.bar!
22
+ api.get.foo.bar.!
23
+
24
+ expect(stub).to have_been_requested.times(2)
25
+ end
26
+
27
+ it 'requests endpoints using subscript operator' do
28
+ stub = stub_request(:get, "http://example.com/foo/bar?fizz=buzz&foo=bar").
29
+ with(:headers => all_the_headers)
30
+
31
+ api.get['foo']['bar'].!
32
+
33
+ expect(stub).to have_been_requested
34
+ end
35
+
36
+
37
+ it 'requests endpoints with query' do
38
+ stub = stub_request(:get, "http://example.com/foo/bar?baz=qux&fizz=buzz&foo=bar").
39
+ with(:headers => all_the_headers)
40
+
41
+ api.get.foo.bar! query: even_moar_params
42
+
43
+ expect(stub).to have_been_requested
44
+ end
45
+
46
+ it 'requests endpoints with headers' do
47
+ stub = stub_request(:get, "http://example.com/foo/bar?fizz=buzz&foo=bar").
48
+ with(:headers => all_the_headers.merge(even_moar_headers))
49
+
50
+ api.get.foo.bar! headers: even_moar_headers
51
+
52
+ expect(stub).to have_been_requested
53
+ end
54
+
55
+ it 'requests endpoints with body' do
56
+ stub = stub_request(:post, "http://example.com/foo/bar?fizz=buzz&foo=bar").
57
+ with(:headers => all_the_headers, :body => test_body)
58
+
59
+ api.post.foo.bar! body: test_body
60
+
61
+ expect(stub).to have_been_requested
62
+ end
63
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ Some::API.send :include, WebMock::API
4
+
5
+ describe 'Some::API stubs' do
6
+
7
+ let(:moar_headers) { { 'X-Fizz' => 'Buzz' } }
8
+ let(:moar_params) { { 'fizz' => 'buzz' } }
9
+ let(:all_the_headers) { test_headers.merge moar_headers }
10
+ let(:all_the_params) { test_params.merge moar_params }
11
+ let(:test_body) { { 'baz' => 'qux' } }
12
+
13
+ let(:even_moar_headers) { { 'X-Baz' => 'Qux' } }
14
+ let(:even_moar_params) { { 'baz' => 'qux' } }
15
+
16
+ let(:api) { TestAPI.new query: moar_params,
17
+ headers: moar_headers }
18
+
19
+ it 'stubs endpoints using method_missing' do
20
+ stub = api.stub.get.foo.bar!
21
+ stub2 = api.stub.get.foo.bar.!
22
+
23
+ HTTParty.get('http://example.com/foo/bar?fizz=buzz&foo=bar',
24
+ headers: all_the_headers)
25
+
26
+ expect(stub).to have_been_requested
27
+ expect(stub2).to have_been_requested
28
+ end
29
+
30
+ it 'stubs endpoints using subscript operator' do
31
+ stub = api.stub.get['foo']['bar'].!
32
+
33
+ HTTParty.get('http://example.com/foo/bar?fizz=buzz&foo=bar',
34
+ headers: all_the_headers)
35
+
36
+ expect(stub).to have_been_requested
37
+ end
38
+
39
+ it 'stubs endpoints with query' do
40
+ stub = api.stub.get.foo.bar! query: even_moar_params
41
+
42
+ HTTParty.get('http://example.com/foo/bar?baz=qux&fizz=buzz&foo=bar',
43
+ headers: all_the_headers)
44
+
45
+ expect(stub).to have_been_requested
46
+ end
47
+
48
+ it 'stubs endpoints with headers' do
49
+ stub = api.stub.get.foo.bar! headers: even_moar_headers
50
+
51
+ HTTParty.get('http://example.com/foo/bar?fizz=buzz&foo=bar',
52
+ headers: all_the_headers.merge(even_moar_headers))
53
+
54
+ expect(stub).to have_been_requested
55
+ end
56
+
57
+ it 'stubs endpoints with body' do
58
+ stub = api.stub.post.foo.bar! body: test_body
59
+
60
+ HTTParty.post('http://example.com/foo/bar?fizz=buzz&foo=bar',
61
+ headers: all_the_headers,
62
+ body: test_body)
63
+
64
+ expect(stub).to have_been_requested
65
+ end
66
+ end
@@ -0,0 +1,66 @@
1
+ require 'someapi'
2
+ require 'webmock/rspec'
3
+ require 'httparty'
4
+
5
+ # Requires supporting ruby files with custom matchers and macros, etc,
6
+ # in spec/support/ and its subdirectories.
7
+ Dir["./spec/support/**/*.rb"].each { |f| require f }
8
+
9
+ RSpec.configure do |config|
10
+ # These two settings work together to allow you to limit a spec run
11
+ # to individual examples or groups you care about by tagging them with
12
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
13
+ # get run.
14
+ config.filter_run :focus
15
+ config.run_all_when_everything_filtered = true
16
+
17
+ # Many RSpec users commonly either run the entire suite or an individual
18
+ # file, and it's useful to allow more verbose output when running an
19
+ # individual spec file.
20
+ if config.files_to_run.one?
21
+ # Use the documentation formatter for detailed output,
22
+ # unless a formatter has already been configured
23
+ # (e.g. via a command-line flag).
24
+ config.default_formatter = 'doc'
25
+ end
26
+
27
+ # Print the 10 slowest examples and example groups at the
28
+ # end of the spec run, to help surface which specs are running
29
+ # particularly slow.
30
+ #config.profile_examples = 10
31
+
32
+ # Run specs in random order to surface order dependencies. If you find an
33
+ # order dependency and want to debug it, you can fix the order by providing
34
+ # the seed, which is printed after each run.
35
+ # --seed 1234
36
+ config.order = :random
37
+
38
+ # Seed global randomization in this process using the `--seed` CLI option.
39
+ # Setting this allows you to use `--seed` to deterministically reproduce
40
+ # test failures related to randomization by passing the same `--seed` value
41
+ # as the one that triggered the failure.
42
+ Kernel.srand config.seed
43
+
44
+ # rspec-expectations config goes here. You can use an alternate
45
+ # assertion/expectation library such as wrong or the stdlib/minitest
46
+ # assertions if you prefer.
47
+ config.expect_with :rspec do |expectations|
48
+ # Enable only the newer, non-monkey-patching expect syntax.
49
+ # For more details, see:
50
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
51
+ expectations.syntax = :expect
52
+ end
53
+
54
+ # rspec-mocks config goes here. You can use an alternate test double
55
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
56
+ config.mock_with :rspec do |mocks|
57
+ # Enable only the newer, non-monkey-patching expect syntax.
58
+ # For more details, see:
59
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
60
+ mocks.syntax = :expect
61
+
62
+ # Prevents you from mocking or stubbing a method that does not exist on
63
+ # a real object. This is generally recommended.
64
+ mocks.verify_partial_doubles = true
65
+ end
66
+ end
@@ -0,0 +1,13 @@
1
+ def test_headers
2
+ { 'X-Hello' => 'World' }
3
+ end
4
+
5
+ def test_params
6
+ { 'foo' => 'bar' }
7
+ end
8
+
9
+ class TestAPI < Some::API
10
+ base_uri 'http://example.com/'
11
+ headers test_headers
12
+ default_params test_params
13
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: someapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-20 00:00:00.000000000 Z
11
+ date: 2014-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.13.1
19
+ version: '0.13'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.13.1
26
+ version: '0.13'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -42,16 +42,44 @@ dependencies:
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '10.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '0'
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.18'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.18'
55
83
  description: Built around HTTParty, SomeAPI provides a generic wrapper for your favourite
56
84
  RESTful WebAPI. Simply extend Some::API and apply your usual HTTParty options like
57
85
  base_uri, then call your new API and party harder!
@@ -62,6 +90,9 @@ extensions: []
62
90
  extra_rdoc_files: []
63
91
  files:
64
92
  - ".gitignore"
93
+ - ".rspec"
94
+ - ".ruby-version"
95
+ - ".travis.yml"
65
96
  - Gemfile
66
97
  - LICENSE.txt
67
98
  - README.md
@@ -69,6 +100,10 @@ files:
69
100
  - lib/someapi.rb
70
101
  - lib/someapi/version.rb
71
102
  - someapi.gemspec
103
+ - spec/someapi_spec.rb
104
+ - spec/someapi_stub_spec.rb
105
+ - spec/spec_helper.rb
106
+ - spec/support/test_api.rb
72
107
  homepage: https://github.com/jellymann/someapi
73
108
  licenses:
74
109
  - MIT
@@ -81,7 +116,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
116
  requirements:
82
117
  - - ">="
83
118
  - !ruby/object:Gem::Version
84
- version: '0'
119
+ version: 1.9.3
85
120
  required_rubygems_version: !ruby/object:Gem::Requirement
86
121
  requirements:
87
122
  - - ">="
@@ -93,4 +128,8 @@ rubygems_version: 2.3.0
93
128
  signing_key:
94
129
  specification_version: 4
95
130
  summary: A generic RESTful API wrapper.
96
- test_files: []
131
+ test_files:
132
+ - spec/someapi_spec.rb
133
+ - spec/someapi_stub_spec.rb
134
+ - spec/spec_helper.rb
135
+ - spec/support/test_api.rb