jeckle 0.2.1 → 0.3.0

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: cc145a2c57d49e16a1eb949572d0e5d5b332e84c
4
- data.tar.gz: d9777c608e3647a7a4280c9d2b6a9c7accb0156e
3
+ metadata.gz: 0fedf58b9859236e613f70bb3cfaf8f34fcba6cd
4
+ data.tar.gz: f5671e5ec06652de45455208795669c487decaa8
5
5
  SHA512:
6
- metadata.gz: 0ce7714c1ba50c9feafa7327766f9eb8d8e5d515c02e9928519eeb6f9b8f7f60e272d68bc0b7ef6080a31218c1a3b4f94f647fa04b7d4c53d8d270c1160dc4c7
7
- data.tar.gz: d5aa1c13218e74e196d08b9236e2f2b5c35a232aca955c8d0aabcba610adc823722f33fc240b8f1b4dc5fabc42989f2ff23d79ac66b9c2989a15904c8d959824
6
+ metadata.gz: d052c4ef86214fcd06f9f84c9f959e02c5c83c2d3560652f8d0fb5206f3a090f8b09d8662cd500bb125206f20cd3d7f44d2dcf33a464bfdbac66b7f99ef6d0a1
7
+ data.tar.gz: 58f383cc88ac992dbef23a98e2c5af620d0c14fdf774373f8a8aa9f07a0b0f722ee496caa03769fd4324c6e7b3e060c0f65bb12f0e424e8ddb56b18da4a86ffc
data/History.markdown ADDED
@@ -0,0 +1,11 @@
1
+ ## v.0.3.0
2
+
3
+ * Change Jeckle::Resource.default_api to Jeckle::Resource.api
4
+
5
+ ## v.0.2.1
6
+
7
+ * Fix bug when APIs includes root in json responses
8
+
9
+ ## v.0.2.0
10
+
11
+ * Add Jeckle middlewares
data/README.md CHANGED
@@ -56,7 +56,7 @@ module SomeService
56
56
  class MyResource
57
57
  include Jeckle::Resource
58
58
 
59
- default_api :some_service
59
+ api :some_service
60
60
 
61
61
  attribute :id
62
62
  end
data/examples/dribbble.rb CHANGED
@@ -9,7 +9,7 @@ end
9
9
  class Shot
10
10
  include Jeckle::Resource
11
11
 
12
- default_api :dribbble
12
+ api :dribbble
13
13
 
14
14
  attribute :id, Integer
15
15
  attribute :name, String
@@ -0,0 +1,79 @@
1
+ module Jeckle
2
+ module HTTP
3
+ def self.included(base)
4
+ base.extend Jeckle::HTTP::APIMapping
5
+ end
6
+
7
+ module APIMapping
8
+ def inherited(base)
9
+ base.class_eval do
10
+ @api_mapping = superclass.api_mapping.dup
11
+ end
12
+ end
13
+
14
+ # The name of the resource that Jeckle uses to make the request
15
+ #
16
+ # @example
17
+ #
18
+ # module Dribble
19
+ # class Shot
20
+ # include Jeckle::Resource
21
+ # end
22
+ # end
23
+ #
24
+ # Shot.resource_name # => Will request for '/shots' resource
25
+ #
26
+ # To overwrite this behaviour, rewrite the resource name method in the class:
27
+ #
28
+ # module OtherApi
29
+ # class Project
30
+ # include Jeckle::Resource
31
+ #
32
+ # def self.resource_name
33
+ # '/project'
34
+ # end
35
+ # end
36
+ # end
37
+ #
38
+ def resource_name
39
+ @resource_name ||= model_name.element.pluralize
40
+ end
41
+
42
+ # The API name that Jeckle uses to find all the api settings like domain, headers, etc.
43
+ #
44
+ # @example
45
+ #
46
+ # Jeckle.configure do |config|
47
+ # config.register :dribbble do |api|
48
+ # api.base_uri = 'http://api.dribbble.com'
49
+ # end
50
+ # end
51
+ #
52
+ # class Shot
53
+ # include Jeckle::Resource
54
+ # api :dribbble
55
+ # end
56
+ #
57
+ def api(registered_api_name)
58
+ api_mapping[:default_api] = Jeckle::Setup.registered_apis.fetch(registered_api_name)
59
+ rescue KeyError => e
60
+ raise Jeckle::NoSuchAPIError, registered_api_name
61
+ end
62
+
63
+ # @deprecated Please use {#api} instead
64
+ #
65
+ def default_api(registered_api_name)
66
+ warn "[DEPRECATION] `default_api` is deprecated. Please use `api` instead."
67
+ api(registered_api_name)
68
+ end
69
+
70
+ def api_mapping
71
+ @api_mapping ||= {}
72
+ end
73
+
74
+ def run_request(endpoint, options = {})
75
+ Jeckle::Request.run api_mapping[:default_api], endpoint, options
76
+ end
77
+ end
78
+ end
79
+ end
@@ -5,8 +5,8 @@ module Jeckle
5
5
  def initialize(api, endpoint, options = {})
6
6
  @api = api
7
7
 
8
- @method = options.delete(:method) || :get
9
- @body = options.delete(:body) if %w(post put).include?(method.to_s)
8
+ @method = options.delete(:method) || :get
9
+ @body = options.delete(:body) if %w(post put).include?(method.to_s)
10
10
  @headers = options.delete(:headers)
11
11
 
12
12
  @endpoint = endpoint
@@ -24,8 +24,8 @@ module Jeckle
24
24
  def perform_api_request
25
25
  api.connection.public_send method do |api_request|
26
26
  api_request.url endpoint
27
- api_request.params = params
28
- api_request.body = body
27
+ api_request.params = params
28
+ api_request.body = body
29
29
  api_request.headers = api_request.headers.merge(headers) if headers
30
30
  end
31
31
  end
@@ -1,50 +1,11 @@
1
1
  module Jeckle
2
2
  module Resource
3
3
  def self.included(base)
4
- base.send :include, Jeckle::Model
5
4
  base.send :include, ActiveModel::Naming
6
5
 
7
- base.send :extend, Jeckle::Resource::ClassMethods
8
- end
9
-
10
- module ClassMethods
11
- def inherited(base)
12
- base.class_eval do
13
- @api_mapping = superclass.api_mapping.dup
14
- end
15
- end
16
-
17
- def resource_name
18
- model_name.element.pluralize
19
- end
20
-
21
- def default_api(registered_api_name)
22
- api_mapping[:default_api] = Jeckle::Setup.registered_apis.fetch(registered_api_name)
23
- rescue KeyError => e
24
- raise Jeckle::NoSuchAPIError, registered_api_name
25
- end
26
-
27
- def api_mapping
28
- @api_mapping ||= {}
29
- end
30
-
31
- def find(id)
32
- endpoint = "#{resource_name}/#{id}"
33
- attributes = run_request(endpoint).response.body
34
-
35
- new attributes
36
- end
37
-
38
- def search(params = {})
39
- response = run_request(resource_name, params).response.body || []
40
- collection = response.kind_of?(Array) ? response : response[resource_name]
41
-
42
- Array(collection).collect { |attrs| new attrs }
43
- end
44
-
45
- def run_request(endpoint, options = {})
46
- Jeckle::Request.run api_mapping[:default_api], endpoint, options
47
- end
6
+ base.send :include, Jeckle::Model
7
+ base.send :include, Jeckle::HTTP
8
+ base.send :include, Jeckle::RESTActions
48
9
  end
49
10
  end
50
11
  end
@@ -0,0 +1,23 @@
1
+ module Jeckle
2
+ module RESTActions
3
+ def self.included(base)
4
+ base.send :extend, Jeckle::RESTActions::Collection
5
+ end
6
+
7
+ module Collection
8
+ def find(id)
9
+ endpoint = "#{resource_name}/#{id}"
10
+ attributes = run_request(endpoint).response.body
11
+
12
+ new attributes
13
+ end
14
+
15
+ def search(params = {})
16
+ response = run_request(resource_name, params).response.body || []
17
+ collection = response.kind_of?(Array) ? response : response[resource_name]
18
+
19
+ Array(collection).collect { |attrs| new attrs }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Jeckle
2
- VERSION = '0.2.1'
2
+ VERSION = '0.3.0'
3
3
  end
data/lib/jeckle.rb CHANGED
@@ -5,7 +5,7 @@ require 'virtus'
5
5
 
6
6
  require 'jeckle/version'
7
7
 
8
- %w(setup api model request resource errors).each do |file_name|
8
+ %w(setup api model request http rest_actions resource errors).each do |file_name|
9
9
  require "jeckle/#{file_name}"
10
10
  end
11
11
 
@@ -1,31 +1,33 @@
1
- Jeckle::Setup.register(:my_super_api) do |api|
2
- api.base_uri = 'http://my-super-api.com.br'
3
- api.headers = { 'Content-Type' => 'application/json' }
4
- api.logger = Logger.new(STDOUT)
5
- api.basic_auth = { username: 'steven_seagal', password: 'youAlwaysLose' }
6
- api.namespaces = { prefix: 'api', version: 'v1' }
7
- api.params = { hello: 'world' }
8
- api.open_timeout = 2
9
- api.read_timeout = 5
1
+ Jeckle.configure do |config|
2
+ config.register :my_super_api do |api|
3
+ api.base_uri = 'http://my-super-api.com.br'
4
+ api.headers = { 'Content-Type' => 'application/json' }
5
+ api.logger = Logger.new(STDOUT)
6
+ api.basic_auth = { username: 'steven_seagal', password: 'youAlwaysLose' }
7
+ api.namespaces = { prefix: 'api', version: 'v1' }
8
+ api.params = { hello: 'world' }
9
+ api.open_timeout = 2
10
+ api.read_timeout = 5
10
11
 
11
- api.middlewares do
12
- request :json
13
- response :json
14
- response :raise_error
12
+ api.middlewares do
13
+ request :json
14
+ response :json
15
+ response :raise_error
16
+ end
15
17
  end
16
- end
17
18
 
18
- Jeckle::Setup.register(:another_api) do |api|
19
- api.base_uri = 'http://another-api.com.br'
20
- api.headers = { 'Content-Type' => 'application/json' }
21
- api.logger = Logger.new(STDOUT)
22
- api.basic_auth = { username: 'heisenberg', password: 'metaAfetaAMina' }
23
- api.namespaces = { prefix: 'api', version: 'v5' }
24
- api.params = { hi: 'there' }
19
+ config.register :another_api do |api|
20
+ api.base_uri = 'http://another-api.com.br'
21
+ api.headers = { 'Content-Type' => 'application/json' }
22
+ api.logger = Logger.new(STDOUT)
23
+ api.basic_auth = { username: 'heisenberg', password: 'metaAfetaAMina' }
24
+ api.namespaces = { prefix: 'api', version: 'v5' }
25
+ api.params = { hi: 'there' }
25
26
 
26
- api.middlewares do
27
- request :json
28
- response :json
29
- response :raise_error
27
+ api.middlewares do
28
+ request :json
29
+ response :json
30
+ response :raise_error
31
+ end
30
32
  end
31
33
  end
@@ -1,7 +1,7 @@
1
1
  class FakeResource
2
2
  include Jeckle::Resource
3
3
 
4
- default_api :my_super_api
4
+ api :my_super_api
5
5
 
6
6
  attribute :id, Integer
7
7
  end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Jeckle::HTTP do
4
+ describe '.resource_name' do
5
+ it 'returns resource name based on class name' do
6
+ expect(FakeResource.resource_name).to eq 'fake_resources'
7
+ end
8
+
9
+ context 'when resource class is namespaced' do
10
+ before do
11
+ MySuperApi = Module.new
12
+ MySuperApi::FakeResource = Class.new(::FakeResource)
13
+ end
14
+
15
+ it 'ignores namespace' do
16
+ expect(MySuperApi::FakeResource.resource_name).to eq 'fake_resources'
17
+ end
18
+ end
19
+ end
20
+
21
+ describe '.api_mapping' do
22
+ it 'returns a hash containing default api' do
23
+ expect(FakeResource.api_mapping).to match(
24
+ default_api: an_instance_of(Jeckle::API)
25
+ )
26
+ end
27
+
28
+ context 'when resource is inherited' do
29
+ let(:inherited_class) { Class.new(FakeResource) }
30
+
31
+ it "contains the parent's api_mapping" do
32
+ expect(inherited_class.api_mapping).to eq FakeResource.api_mapping
33
+ end
34
+
35
+ context 'when api_mapping is changed' do
36
+ it "does not affect the parent" do
37
+ inherited_class.api :another_api
38
+
39
+ expect(FakeResource.api_mapping).not_to eq inherited_class.api_mapping
40
+ expect(FakeResource.api_mapping[:default_api]).to eq Jeckle::Setup.registered_apis[:my_super_api]
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ describe '.default_api' do
47
+ context 'when defining a registered API via Jeckle::Setup' do
48
+ it 'returns the assigned API' do
49
+ expect(FakeResource.api :my_super_api).to be_kind_of Jeckle::API
50
+ end
51
+
52
+ it 'assigns API do api_mapping' do
53
+ expect(FakeResource.api_mapping).to have_key :default_api
54
+ end
55
+ end
56
+
57
+ context 'when defining an inexistent API' do
58
+ it 'raises NoSuchAPIError' do
59
+ expect { FakeResource.api :unknown_api }.to raise_error Jeckle::NoSuchAPIError
60
+ end
61
+ end
62
+ end
63
+ end
@@ -3,8 +3,6 @@ require 'spec_helper'
3
3
  RSpec.describe Jeckle::Resource do
4
4
  subject(:fake_resource) { FakeResource.new }
5
5
 
6
- let(:api) { FakeResource.api_mapping[:default_api] }
7
-
8
6
  it 'includes jeckle/model' do
9
7
  expect(FakeResource.ancestors).to include Jeckle::Model
10
8
  end
@@ -13,131 +11,11 @@ RSpec.describe Jeckle::Resource do
13
11
  expect(FakeResource.ancestors).to include ActiveModel::Naming
14
12
  end
15
13
 
16
- describe '.resource_name' do
17
- it 'returns resource name based on class name' do
18
- expect(FakeResource.resource_name).to eq 'fake_resources'
19
- end
20
-
21
- context 'when resource class is namespaced' do
22
- before do
23
- MySuperApi = Module.new
24
- MySuperApi::FakeResource = Class.new(::FakeResource)
25
- end
26
-
27
- it 'ignores namespace' do
28
- expect(MySuperApi::FakeResource.resource_name).to eq 'fake_resources'
29
- end
30
- end
31
- end
32
-
33
- describe '.api_mapping' do
34
- it 'returns a hash containing default api' do
35
- expect(FakeResource.api_mapping).to match(
36
- default_api: an_instance_of(Jeckle::API)
37
- )
38
- end
39
-
40
- context 'when resource is inherited' do
41
- let(:inherited_class) { Class.new(FakeResource) }
42
-
43
- it "contains the parent's api_mapping" do
44
- expect(inherited_class.api_mapping).to eq FakeResource.api_mapping
45
- end
46
-
47
- context 'when api_mapping is changed' do
48
- it "does not affect the parent" do
49
- inherited_class.default_api :another_api
50
-
51
- expect(FakeResource.api_mapping).not_to eq inherited_class.api_mapping
52
- expect(FakeResource.api_mapping[:default_api]).to eq Jeckle::Setup.registered_apis[:my_super_api]
53
- end
54
- end
55
- end
56
- end
57
-
58
- describe '.default_api' do
59
- context 'when defining a registered API via Jeckle::Setup' do
60
- it 'returns the assigned API' do
61
- expect(FakeResource.default_api :my_super_api).to be_kind_of Jeckle::API
62
- end
63
-
64
- it 'assigns API do api_mapping' do
65
- expect(FakeResource.api_mapping).to have_key :default_api
66
- end
67
- end
68
-
69
- context 'when defining an inexistent API' do
70
- it 'raises NoSuchAPIError' do
71
- expect { FakeResource.default_api :unknown_api }.to raise_error Jeckle::NoSuchAPIError
72
- end
73
- end
14
+ it 'includes jeckle http' do
15
+ expect(FakeResource.ancestors).to include Jeckle::HTTP
74
16
  end
75
17
 
76
- describe '.find' do
77
- let(:fake_request) { OpenStruct.new response: OpenStruct.new(body: { id: 1001 }) }
78
-
79
- it 'calls default API connection with GET' do
80
- expect(Jeckle::Request).to receive(:run)
81
- .with(api, 'fake_resources/1001', {}).and_return(fake_request)
82
-
83
- FakeResource.find 1001
84
- end
85
-
86
- it 'returns an instance of resource' do
87
- allow(Jeckle::Request).to receive(:run).and_return(fake_request)
88
-
89
- expect(FakeResource.find 1001).to be_an_instance_of(FakeResource)
90
- end
91
- end
92
-
93
- describe '.search' do
94
- let(:fake_request) { OpenStruct.new response: OpenStruct.new(body: body) }
95
-
96
- let(:query) { { name: 'cocada' } }
97
-
98
- context 'when there are results WITHOUT root node' do
99
- let(:body) { [{ id: 1001 }, { id: 1002 }] }
100
-
101
- it 'calls default API connection with GET and search params' do
102
- expect(Jeckle::Request).to receive(:run)
103
- .with(api, 'fake_resources', query).and_return(fake_request)
104
-
105
- FakeResource.search query
106
- end
107
-
108
- it 'returns an Array of resources' do
109
- allow(Jeckle::Request).to receive(:run).and_return(fake_request)
110
-
111
- expect(FakeResource.search query).to match [
112
- an_instance_of(FakeResource),
113
- an_instance_of(FakeResource)
114
- ]
115
- end
116
- end
117
-
118
- context 'when there are results WITH root node' do
119
- let(:body) do
120
- { 'fake_resources' => [{ id: 1001 }, { id: 1002 } ] }
121
- end
122
-
123
- it 'returns an Array of resources' do
124
- allow(Jeckle::Request).to receive(:run).and_return(fake_request)
125
-
126
- expect(FakeResource.search query).to match [
127
- an_instance_of(FakeResource),
128
- an_instance_of(FakeResource)
129
- ]
130
- end
131
- end
132
-
133
- context 'when there are no results' do
134
- let(:fake_request) { OpenStruct.new response: OpenStruct.new(body: nil) }
135
-
136
- it 'returns an empty Array' do
137
- allow(Jeckle::Request).to receive(:run).and_return(fake_request)
138
-
139
- expect(FakeResource.search query).to match []
140
- end
141
- end
18
+ it 'includes jeckle rest actions' do
19
+ expect(FakeResource.ancestors).to include Jeckle::RESTActions
142
20
  end
143
21
  end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Jeckle::RESTActions do
4
+ let(:api) { FakeResource.api_mapping[:default_api] }
5
+
6
+ describe '.find' do
7
+ let(:fake_request) { OpenStruct.new response: OpenStruct.new(body: { id: 1001 }) }
8
+
9
+ it 'calls default API connection with GET' do
10
+ expect(Jeckle::Request).to receive(:run)
11
+ .with(api, 'fake_resources/1001', {}).and_return(fake_request)
12
+
13
+ FakeResource.find 1001
14
+ end
15
+
16
+ it 'returns an instance of resource' do
17
+ allow(Jeckle::Request).to receive(:run).and_return(fake_request)
18
+
19
+ expect(FakeResource.find 1001).to be_an_instance_of(FakeResource)
20
+ end
21
+ end
22
+
23
+ describe '.search' do
24
+ let(:fake_request) { OpenStruct.new response: OpenStruct.new(body: body) }
25
+
26
+ let(:query) { { name: 'cocada' } }
27
+
28
+ context 'when there are results WITHOUT root node' do
29
+ let(:body) { [{ id: 1001 }, { id: 1002 }] }
30
+
31
+ it 'calls default API connection with GET and search params' do
32
+ expect(Jeckle::Request).to receive(:run)
33
+ .with(api, 'fake_resources', query).and_return(fake_request)
34
+
35
+ FakeResource.search query
36
+ end
37
+
38
+ it 'returns an Array of resources' do
39
+ allow(Jeckle::Request).to receive(:run).and_return(fake_request)
40
+
41
+ expect(FakeResource.search query).to match [
42
+ an_instance_of(FakeResource),
43
+ an_instance_of(FakeResource)
44
+ ]
45
+ end
46
+ end
47
+
48
+ context 'when there are results WITH root node' do
49
+ let(:body) do
50
+ { 'fake_resources' => [{ id: 1001 }, { id: 1002 } ] }
51
+ end
52
+
53
+ it 'returns an Array of resources' do
54
+ allow(Jeckle::Request).to receive(:run).and_return(fake_request)
55
+
56
+ expect(FakeResource.search query).to match [
57
+ an_instance_of(FakeResource),
58
+ an_instance_of(FakeResource)
59
+ ]
60
+ end
61
+ end
62
+
63
+ context 'when there are no results' do
64
+ let(:fake_request) { OpenStruct.new response: OpenStruct.new(body: nil) }
65
+
66
+ it 'returns an empty Array' do
67
+ allow(Jeckle::Request).to receive(:run).and_return(fake_request)
68
+
69
+ expect(FakeResource.search query).to match []
70
+ end
71
+ end
72
+ end
73
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeckle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomas D'Stefano
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-16 00:00:00.000000000 Z
12
+ date: 2014-10-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -135,6 +135,7 @@ files:
135
135
  - .rspec
136
136
  - .travis.yml
137
137
  - Gemfile
138
+ - History.markdown
138
139
  - LICENSE.txt
139
140
  - README.md
140
141
  - Rakefile
@@ -143,18 +144,22 @@ files:
143
144
  - lib/jeckle.rb
144
145
  - lib/jeckle/api.rb
145
146
  - lib/jeckle/errors.rb
147
+ - lib/jeckle/http.rb
146
148
  - lib/jeckle/model.rb
147
149
  - lib/jeckle/request.rb
148
150
  - lib/jeckle/resource.rb
151
+ - lib/jeckle/rest_actions.rb
149
152
  - lib/jeckle/setup.rb
150
153
  - lib/jeckle/version.rb
151
154
  - spec/fixtures/jeckle_config.rb
152
155
  - spec/fixtures/models/fake_model.rb
153
156
  - spec/fixtures/resources/fake_resource.rb
154
157
  - spec/jeckle/api_spec.rb
158
+ - spec/jeckle/http_spec.rb
155
159
  - spec/jeckle/model_spec.rb
156
160
  - spec/jeckle/request_spec.rb
157
161
  - spec/jeckle/resource_spec.rb
162
+ - spec/jeckle/rest_actions_spec.rb
158
163
  - spec/jeckle/setup_spec.rb
159
164
  - spec/spec_helper.rb
160
165
  - spec/support/shared_examples.rb
@@ -187,9 +192,11 @@ test_files:
187
192
  - spec/fixtures/models/fake_model.rb
188
193
  - spec/fixtures/resources/fake_resource.rb
189
194
  - spec/jeckle/api_spec.rb
195
+ - spec/jeckle/http_spec.rb
190
196
  - spec/jeckle/model_spec.rb
191
197
  - spec/jeckle/request_spec.rb
192
198
  - spec/jeckle/resource_spec.rb
199
+ - spec/jeckle/rest_actions_spec.rb
193
200
  - spec/jeckle/setup_spec.rb
194
201
  - spec/spec_helper.rb
195
202
  - spec/support/shared_examples.rb