api-client 1.10.0 → 2.0.0.rc1

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.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v1.10.0
4
+
5
+ * Add Support for api responses with collections
6
+
3
7
  ## v1.9.1
4
8
 
5
9
  * Fix for Net::Http on NotFound Exception
data/README.md CHANGED
@@ -66,7 +66,15 @@ class User < ApiClient::Base
66
66
  Then, on your action, just put into it:
67
67
 
68
68
  ```ruby
69
- @user = User.get("http://api.example.com/user/3")
69
+ @user = User.get(3)
70
+ ```
71
+
72
+ where 3 is the id of the user.
73
+
74
+ To a request that returns a collection of the object, use:
75
+
76
+ ```ruby
77
+ @user = User.collection
70
78
  ```
71
79
 
72
80
  ## Advanced Usage
@@ -104,4 +112,4 @@ This code will create a setter and a getter for houses and cars and initialize t
104
112
  2. Create your feature branch (`git checkout -b my-new-feature`)
105
113
  3. Commit your changes (`git commit -am 'Added some feature'`)
106
114
  4. Push to the branch (`git push origin my-new-feature`)
107
- 5. Create new Pull Request
115
+ 5. Create new Pull Request
data/api-client.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
9
9
  gem.summary = %q{Client to make Api calls}
10
10
 
11
11
  gem.files = `git ls-files`.split("\n")
12
- gem.test_files = `git ls-files -- {test,spec,features, gemfiles}/*`.split("\n")
12
+ gem.test_files = `git ls-files -- {test,spec,features,examples,gemfiles}/*`.split("\n")
13
13
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
14
14
  gem.require_paths = %w(lib)
15
15
 
@@ -0,0 +1,5 @@
1
+ # Global Configuration
2
+ # Api path
3
+ ApiClient.configure do |config|
4
+ config.path = "http://api.example.com"
5
+ end
@@ -1,38 +1,45 @@
1
+ # It will works with respond_with.
2
+ # Your action should looks like any other one: A model with a method call. =D
1
3
  class UserController < ApplicationController
2
- # It will works with respond_with.
3
- # Your action should looks like any other one: A model with a method call. =D
4
+ # It will hit http://api.example.com/users with a get request
4
5
  def index
5
- @users = User.get("api.example.com/users")
6
+ @users = User.collection
6
7
  respond_with(@users)
7
8
  end
8
9
 
10
+ # It will initialize a new object based on the attribute accessors
9
11
  def new
10
12
  @user = User.new
11
13
  respond_with(@user)
12
14
  end
13
15
 
16
+ # It will hit http://api.example.com/users with a post request
14
17
  def create
15
- @user = User.post("api.example.com/users", :user => params[:user])
18
+ @user = User.post("", :user => params[:user])
16
19
  respond_with(@user)
17
20
  end
18
21
 
22
+ # It will hit http://api.example.com/users/1 with a get request
19
23
  def edit
20
- @user = User.get("api.example.com/users/#{params[:id]}")
24
+ @user = User.get(params[:id])
21
25
  respond_with(@user)
22
26
  end
23
27
 
28
+ # It will hit http://api.example.com/users/1 with a patch request
24
29
  def update
25
- @user = User.patch("api.example.com/users", { :id => params[:id], :user => params[:user]})
30
+ @user = User.patch("", { :id => params[:id], :user => params[:user] })
26
31
  respond_with(@user)
27
32
  end
28
33
 
34
+ # It will hit http://api.example.com/users/1 with a get request
29
35
  def show
30
- @user = User.get("api.example.com/users/#{params[:id]}")
36
+ @user = User.get(params[:id])
31
37
  respond_with(@user)
32
38
  end
33
39
 
40
+ # It will hit http://api.example.com/users/1 with a delete request
34
41
  def delete
35
- @user = User.delete("api.example.com/users/#{params[:id]}")
42
+ @user = User.delete(params[:id])
36
43
  respond_with(@user)
37
44
  end
38
- end
45
+ end
@@ -8,4 +8,4 @@ class Admin < ApiClient::Base
8
8
  # Validations will work as well
9
9
  validates :email, :presence => true, :uniqueness => true
10
10
  validates :password, :confirmation => true
11
- end
11
+ end
@@ -1,3 +1,3 @@
1
1
  class Group < ApiClient::Base
2
2
  self.associations = { :members => "User", :owner => "Admin" }
3
- end
3
+ end
@@ -7,4 +7,4 @@ class User < ApiClient::Base
7
7
  # Validations will work as well
8
8
  validates :email, :presence => true, :uniqueness => true
9
9
  validates :password, :confirmation => true
10
- end
10
+ end
data/lib/api-client.rb CHANGED
@@ -7,9 +7,10 @@ module ApiClient
7
7
  autoload :Configuration, 'api-client/configuration'
8
8
  autoload :Base, 'api-client/base'
9
9
  autoload :Collection, 'api-client/collection'
10
+ autoload :ClassMethods, 'api-client/class_methods'
11
+ autoload :InstanceMethods, 'api-client/instance_methods'
10
12
  autoload :Dispatcher, 'api-client/dispatcher'
11
13
  autoload :Parser, 'api-client/parser'
12
- autoload :Builder, 'api-client/builder'
13
14
 
14
15
  # Configures global settings
15
16
  # ApiClient.configure do |config|
@@ -27,4 +28,4 @@ module ApiClient
27
28
  configure do |config|
28
29
  config.path = ''
29
30
  end
30
- end
31
+ end
@@ -12,7 +12,8 @@ module ApiClient
12
12
  include ActiveModel::Conversion
13
13
  extend ActiveModel::Naming
14
14
 
15
- extend ApiClient::Builder
15
+ extend ApiClient::ClassMethods
16
+ include ApiClient::InstanceMethods
16
17
 
17
18
  # @return [Hash] the request response.
18
19
  attr_accessor :response
@@ -71,7 +72,7 @@ module ApiClient
71
72
  # Set methods to initialize associated objects.
72
73
  #
73
74
  # @param [Hash] association classes.
74
- def self.associations(associations = {})
75
+ def self.associations=(associations = {})
75
76
  associations.each do |association, class_name|
76
77
  class_eval <<-EVAL
77
78
  def #{association.to_s}=(attributes = {})
@@ -86,7 +87,7 @@ module ApiClient
86
87
  end
87
88
 
88
89
  class << self
89
- alias_method :association, :associations
90
+ alias_method :association=, :associations=
90
91
  end
91
92
 
92
93
  # Overwrite #attr_acessor method to save instance_variable names.
@@ -94,7 +95,7 @@ module ApiClient
94
95
  # @param [Array] instance variables.
95
96
  def self.attr_accessor(*vars)
96
97
  @attributes ||= []
97
- @attributes.concat vars
98
+ @attributes.concat(vars)
98
99
  super
99
100
  end
100
101
 
@@ -119,8 +120,8 @@ module ApiClient
119
120
  #
120
121
  # @param [String] url to get the collection.
121
122
  # @return [Collection] a collection of objects.
122
- def self.collection(url)
123
- ApiClient::Collection.new(self, url).collection
123
+ def self.collection
124
+ ApiClient::Collection.new(self, self.path).collection
124
125
  end
125
126
 
126
127
  # Set the hash of errors, making keys symbolic.
@@ -129,12 +130,5 @@ module ApiClient
129
130
  def errors=(errs = {})
130
131
  errors.add_errors(Hash[errs.map{|(key,value)| [key.to_sym,value]}])
131
132
  end
132
-
133
- protected
134
-
135
- def self.method_missing(method, *args)
136
- @response = ApiClient::Parser.response(ApiClient::Dispatcher.send(method, *args), *args[0])
137
- build(self, @response)
138
- end
139
133
  end
140
- end
134
+ end
@@ -0,0 +1,30 @@
1
+ module ApiClient
2
+ # This module handles the logic to make an api call and initialize an object with the response.
3
+ module ClassMethods
4
+ # Initialize an object based on a hash of attributes.
5
+ #
6
+ # @param [Hash] attributes hash of attributes.
7
+ # @return [Base] the object initialized.
8
+ def build(params)
9
+ if params.key?(remote_object)
10
+ new(params[remote_object].merge(:response => params))
11
+ else
12
+ new(params.merge(:response => params))
13
+ end
14
+ end
15
+
16
+ # Make the api call and pass the parsed response to build to create a new object.
17
+ #
18
+ # @param [Symbol] method_name the name of the method.
19
+ # @param [Integer] id the id of the object.
20
+ # @param [Array] args an array of params.
21
+ # @return [Base] the object initialized.
22
+ def method_missing(method_name, id = nil, *args)
23
+ url = "#{ApiClient.config.path}#{self.path}"
24
+ "#{url}/#{id}" unless id.nil?
25
+ response = ApiClient::Dispatcher.send(method_name.to_sym, url, *args)
26
+ params = ApiClient::Parser.response(response, url)
27
+ build(params)
28
+ end
29
+ end
30
+ end
@@ -9,7 +9,8 @@ class ApiClient::Collection
9
9
  # @param [Class] The class to instantiate the objects.
10
10
  # @param [String] The url to get the data.
11
11
  # @return [Collection] the collection of objects.
12
- def initialize(klass, url)
12
+ def initialize(klass, resource_path)
13
+ url = "#{ApiClient.config.path}#{resource_path}"
13
14
  @collection = ApiClient::Parser.response(ApiClient::Dispatcher.get(url), url)
14
15
  @collection.map! do |attributes|
15
16
  klass.new(attributes)
@@ -0,0 +1,37 @@
1
+ module ApiClient
2
+ # This module handles the logic to make an api call and update the current object with the response.
3
+ module InstanceMethods
4
+ # Update an object based on a hash of attributes.
5
+ #
6
+ # @param [Hash] attributes hash of attributes.
7
+ # @return [Base] the updated object.
8
+ def update(params)
9
+ if params.key?(self.class.remote_object)
10
+ params[self.class.remote_object].each do |key, value|
11
+ instance_variable_set(key.to_sym, value)
12
+ end
13
+ instance_variable_set(response.to_sym, params[self.class.remote_object])
14
+ else
15
+ params.each do |key, value|
16
+ instance_variable_set("@#{key}", value)
17
+ end
18
+ instance_variable_set("@response", params)
19
+ end
20
+ self
21
+ end
22
+
23
+ # Make the api call and pass the parsed response to update the current object.
24
+ #
25
+ # @param [Symbol] method_name the name of the method.
26
+ # @param [Integer] id the id of the current object.
27
+ # @param [Array] args an array of params.
28
+ # @return [Base] the object updated.
29
+ def method_missing(method_name, id = nil, *args)
30
+ url = "#{ApiClient.config.path}#{self.class.path}"
31
+ "#{url}/#{id}" unless id.nil?
32
+ response = ApiClient::Dispatcher.send(method_name.to_sym, url, *args)
33
+ params = ApiClient::Parser.response(response, url)
34
+ update(params)
35
+ end
36
+ end
37
+ end
@@ -1,5 +1,5 @@
1
1
  # High Level Namespace of the library ApiClient.
2
2
  module ApiClient
3
3
  # Version of the library.
4
- VERSION = "1.10.0"
4
+ VERSION = "2.0.0.rc1"
5
5
  end
@@ -118,12 +118,12 @@ describe ApiClient::Base do
118
118
 
119
119
  describe "#collection" do
120
120
  before :each do
121
- ApiClient::Collection.stub(:new).with(User, "http://api.example.com").and_return(collection)
121
+ ApiClient::Collection.stub(:new).with(User, "users").and_return(collection)
122
122
  collection.stub(:collection => [ user, user ])
123
123
  end
124
124
 
125
125
  it "should return a collection of objects" do
126
- User.collection("http://api.example.com").should == [ user, user ]
126
+ User.collection.should == [ user, user ]
127
127
  end
128
128
  end
129
129
 
@@ -138,28 +138,33 @@ describe ApiClient::Base do
138
138
  end
139
139
 
140
140
  describe "requests" do
141
- context "with an object as response" do
141
+ context "on the class" do
142
142
  before :each do
143
- stub_request(:any, "http://api.example.com").to_return(:body => {"a" => "b"}.to_json)
143
+ stub_request(:any, "http://api.example.com/users").to_return(:body => {"a" => "b"}.to_json)
144
144
  end
145
145
 
146
146
  it "should return a new instance" do
147
- User.get("http://api.example.com").should be_an_instance_of(User)
147
+ User.get.should be_an_instance_of(User)
148
148
  end
149
149
 
150
150
  it "should set the response on the instance" do
151
- User.get("http://api.example.com").response.should == {"a" => "b"}
151
+ User.get.response.should == {"a" => "b"}
152
152
  end
153
153
  end
154
154
 
155
- context "with an array as response" do
155
+ context "on an object" do
156
156
  before :each do
157
- stub_request(:any, "http://api.example.com").to_return(:body => [{"a" => "b"}].to_json)
157
+ stub_request(:any, "http://api.example.com/users").to_return(:body => {"a" => "b"}.to_json)
158
+ @user = User.new
158
159
  end
159
160
 
160
- it "should return an array of instances" do
161
- User.get("http://api.example.com").should be_an_instance_of(Array)
161
+ it "should return a new instance" do
162
+ @user.get.should be_an_instance_of(User)
163
+ end
164
+
165
+ it "should set the response on the instance" do
166
+ @user.get.response.should == {"a" => "b"}
162
167
  end
163
168
  end
164
169
  end
165
- end
170
+ end
@@ -4,9 +4,9 @@ describe ApiClient::Collection do
4
4
  let(:user) { User.new }
5
5
 
6
6
  before :each do
7
- stub_request(:get, "http://api.example.com").to_return(:body => [ {"a" => "b"}, {"a" => "b2"} ].to_json)
7
+ stub_request(:get, "http://api.example.com/users").to_return(:body => [ {"a" => "b"}, {"a" => "b2"} ].to_json)
8
8
  User.stub(:new => user)
9
- @collection = ApiClient::Collection.new(User, "http://api.example.com")
9
+ @collection = ApiClient::Collection.new(User, "users")
10
10
  end
11
11
 
12
12
  it "should include enumerable module" do
@@ -3,6 +3,12 @@ require 'spec_helper'
3
3
  describe ApiClient::Configuration do
4
4
  describe "#path" do
5
5
  describe "when not configured" do
6
+ before :each do
7
+ ApiClient.configure do |config|
8
+ config.path = ""
9
+ end
10
+ end
11
+
6
12
  it "should raise an error" do
7
13
  lambda { ApiClient.config.path }.should raise_error(ApiClient::Exceptions::NotConfigured)
8
14
  end
@@ -11,7 +17,7 @@ describe ApiClient::Configuration do
11
17
  describe "when properly configured" do
12
18
  before :each do
13
19
  ApiClient.configure do |config|
14
- config.path = "api.example.com"
20
+ config.path = "http://api.example.com"
15
21
  end
16
22
  end
17
23
 
@@ -24,21 +30,21 @@ describe ApiClient::Configuration do
24
30
  describe "#path=" do
25
31
  describe "with a string without '/'" do
26
32
  before :each do
27
- ApiClient.config.path = "api.example.com"
33
+ ApiClient.config.path = "http://api.example.com"
28
34
  end
29
35
 
30
36
  it "should set it with a '/'" do
31
- ApiClient.config.path.should == "api.example.com/"
37
+ ApiClient.config.path.should == "http://api.example.com/"
32
38
  end
33
39
  end
34
40
 
35
41
  describe "with a string with '/'" do
36
42
  before :each do
37
- ApiClient.config.path = "api.example.com/"
43
+ ApiClient.config.path = "http://api.example.com/"
38
44
  end
39
45
 
40
46
  it "should set it as passed" do
41
- ApiClient.config.path.should == "api.example.com/"
47
+ ApiClient.config.path.should == "http://api.example.com/"
42
48
  end
43
49
  end
44
50
  end
data/spec/spec_helper.rb CHANGED
@@ -21,11 +21,15 @@ class Admin < ApiClient::Base
21
21
  end
22
22
 
23
23
  class Post < ApiClient::Base
24
- self.association({ :writer => "User" })
24
+ self.association = { :writer => "User" }
25
25
 
26
26
  attr_accessor :a
27
27
  end
28
28
 
29
29
  class Group < ApiClient::Base
30
- self.associations({ :members => "User", :owner => "Admin" })
30
+ self.associations = { :members => "User", :owner => "Admin" }
31
31
  end
32
+
33
+ ApiClient.configure do |config|
34
+ config.path = 'http://api.example.com'
35
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
5
- prerelease:
4
+ version: 2.0.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Paulo Henrique Lopes Ribeiro
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-04 00:00:00.000000000 Z
12
+ date: 2013-06-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -140,6 +140,7 @@ files:
140
140
  - README.md
141
141
  - Rakefile
142
142
  - api-client.gemspec
143
+ - examples/config/initializers/api-client.rb
143
144
  - examples/controllers/application_controller.rb
144
145
  - examples/controllers/user_controller.rb
145
146
  - examples/models/admin.rb
@@ -149,7 +150,7 @@ files:
149
150
  - gemfiles/Gemfile.typhoeus
150
151
  - lib/api-client.rb
151
152
  - lib/api-client/base.rb
152
- - lib/api-client/builder.rb
153
+ - lib/api-client/class_methods.rb
153
154
  - lib/api-client/collection.rb
154
155
  - lib/api-client/configuration.rb
155
156
  - lib/api-client/dispatcher.rb
@@ -166,6 +167,7 @@ files:
166
167
  - lib/api-client/exceptions/not_found.rb
167
168
  - lib/api-client/exceptions/service_unavailable.rb
168
169
  - lib/api-client/exceptions/unauthorized.rb
170
+ - lib/api-client/instance_methods.rb
169
171
  - lib/api-client/net/http.rb
170
172
  - lib/api-client/parser.rb
171
173
  - lib/api-client/version.rb
@@ -190,16 +192,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
190
192
  version: '0'
191
193
  segments:
192
194
  - 0
193
- hash: 4163480247094767209
195
+ hash: 3711980256019663374
194
196
  required_rubygems_version: !ruby/object:Gem::Requirement
195
197
  none: false
196
198
  requirements:
197
- - - ! '>='
199
+ - - ! '>'
198
200
  - !ruby/object:Gem::Version
199
- version: '0'
200
- segments:
201
- - 0
202
- hash: 4163480247094767209
201
+ version: 1.3.1
203
202
  requirements: []
204
203
  rubyforge_project:
205
204
  rubygems_version: 1.8.25
@@ -1,12 +0,0 @@
1
- module ApiClient
2
- module Builder
3
- def build(object, params)
4
- case true
5
- when params.instance_of?(Array) then return params.map { |a| new(a.merge(:response => params)) }
6
- when params.key?(remote_object) then return new(params[remote_object].merge(:response => params))
7
- when params.key?(remote_object.pluralize) then return params[remote_object.pluralize].map { |a| new(a.merge(:response => params)) }
8
- else return new(params.merge(:response => params))
9
- end
10
- end
11
- end
12
- end