someapi 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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