her 0.6.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NzFmYjMyNGNlODUyZjk4N2I2MzA5ZGZmYjdkNTQyYTQ5YzZiMzlhMw==
4
+ ZGIzMGM1MTY2YmRmZjZjNmJhNzhhOGQ0YjcxZmMxZDM3MTJlNWVlZg==
5
5
  data.tar.gz: !binary |-
6
- ODJkYzM0YTU3YTI3YTI2ZmNlNmIxM2UxOTAzZTc2YTA3NTJjMTM0Zg==
6
+ NTM0Y2JjYWZiNjAxOTJhMTUyZjc0OTYwZjU1YTRkNGViOWM4MTcwZA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ODEzZjJhOTYwNDM0OGI0NGQzYzBmMGVkODdiYjk3NDFkY2E5ZTNkZTRkYWZl
10
- MDlhODA5ZDY4NTJhZjE2MDM1MDIzMjViZDIzMjUxMTdhZDA1OTE4NDliODRj
11
- MDdkMzdiMTI2MzAzNDE4NjkxNDY5ZDRhNmFmNGJjMjlmODcyNjA=
9
+ MTExZDExMjk5ODU5MmQ1Nzg4YmIwNWEyYmJmZDRiMTFiMjdlNTkwNjViNzQw
10
+ YjcxN2MyM2Q2ODlmZmNkODk0OTQyOGUwY2ViMWUwMTViMWI2OTMxYWVmZjNk
11
+ NzQ0MzhiY2JlZGE2YWY4NzIyMTg1YWVhYjgwNTNhYjkzYzVjNjY=
12
12
  data.tar.gz: !binary |-
13
- MTBiODVmMmEzMDI5NTI2NmE0NGMzNDIyNWJkNjRiZTM2YTAxYzc1YjFhMTA4
14
- YTM5NWRmNzVhNjE2Yjc0MDVkYTNiMjYyY2NkMTg2ODYxYjJhZDdlZjYzNmVk
15
- NmYyNDc2M2IwYmVlNWU1YjU3Y2ZmYTE0YmQ1YWMyYjE4ZGM1YzQ=
13
+ YjJiN2Y5NGY5NWRjMTcyOTRiNDgwOGVjMjZmYTYxY2NmNjQ3NDhiNDUwMDg2
14
+ MWFhNWVkNjA3OTBiNzQzOGRkNzU1ZTRlZWJjZmMyYWVmM2VjOTkwOTZlYjU3
15
+ YzYyYjNkYjdhYzNhNTJmYjcyYzY1MGQyYzE1YjE2OWViMmI4ZjM=
data/README.md CHANGED
@@ -670,6 +670,23 @@ end
670
670
  # GET /users?role=admin&active=1
671
671
  ```
672
672
 
673
+ A neat trick you can do with scopes is interact with complex paths.
674
+
675
+ ```ruby
676
+ class User
677
+ include Her::Model
678
+
679
+ collection_path "organizations/:organization_id/users"
680
+ scope :for_organization, -> { |id| where(organization_id: id) }
681
+ end
682
+
683
+ @user = User.for_organization(3).find(2)
684
+ # GET /organizations/3/users/2
685
+
686
+ @user = User.for_organization(3).create(fullname: "Tobias Fünke")
687
+ # POST /organizations/3 with `fullname=Tobias+Fünke`
688
+ ```
689
+
673
690
  ### Multiple APIs
674
691
 
675
692
  It is possible to use different APIs for different models. Instead of calling `Her::API.setup`, you can create instances of `Her::API`:
@@ -834,7 +851,7 @@ See [CONTRIBUTING.md](https://github.com/remiprev/her/blob/master/CONTRIBUTING.m
834
851
 
835
852
  ### Contributors
836
853
 
837
- These fine folks helped with Her:
854
+ These [fine folks](https://github.com/remiprev/her/contributors) helped with Her:
838
855
 
839
856
  * [@jfcixmedia](https://github.com/jfcixmedia)
840
857
  * [@EtienneLem](https://github.com/EtienneLem)
@@ -163,6 +163,13 @@ module Her
163
163
  Her::Model::Attributes.initialize_collection(self, parsed_data)
164
164
  end
165
165
 
166
+ # Initialize a new object with the "raw" parsed_data from the parsing middleware
167
+ #
168
+ # @private
169
+ def new_from_parsed_data(parsed_data)
170
+ new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:metadata], :_errors => parsed_data[:errors])
171
+ end
172
+
166
173
  # Define the attributes that will be used to track dirty attributes and validations
167
174
  #
168
175
  # @param [Array] attributes
@@ -233,7 +240,7 @@ module Her
233
240
  def store_her_data(name, value)
234
241
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
235
242
  if @_her_store_#{name} && value.present?
236
- remove_method @_her_store_#{name}
243
+ remove_method @_her_store_#{name}.to_sym
237
244
  remove_method @_her_store_#{name}.to_s + '='
238
245
  end
239
246
 
@@ -42,11 +42,11 @@ module Her
42
42
  params = to_params
43
43
  self.class.request(to_params.merge(:_method => method, :_path => request_path)) do |parsed_data, response|
44
44
  assign_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
45
- self.metadata = parsed_data[:metadata]
46
- self.response_errors = parsed_data[:errors]
47
- self.changed_attributes.clear if self.changed_attributes.present?
45
+ @metadata = parsed_data[:metadata]
46
+ @response_errors = parsed_data[:errors]
48
47
 
49
- return false if !response.success? || self.response_errors.any?
48
+ return false if !response.success? || @response_errors.any?
49
+ self.changed_attributes.clear if self.changed_attributes.present?
50
50
  end
51
51
  end
52
52
  end
@@ -65,8 +65,8 @@ module Her
65
65
  run_callbacks :destroy do
66
66
  self.class.request(:_method => method, :_path => request_path) do |parsed_data, response|
67
67
  assign_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
68
- self.metadata = parsed_data[:metadata]
69
- self.response_errors = parsed_data[:errors]
68
+ @metadata = parsed_data[:metadata]
69
+ @response_errors = parsed_data[:errors]
70
70
  @destroyed = true
71
71
  end
72
72
  end
@@ -74,37 +74,6 @@ module Her
74
74
  end
75
75
 
76
76
  module ClassMethods
77
- # Fetch specific resource(s) by their ID
78
- #
79
- # @example
80
- # @user = User.find(1)
81
- # # Fetched via GET "/users/1"
82
- #
83
- # @example
84
- # @users = User.find([1, 2])
85
- # # Fetched via GET "/users/1" and GET "/users/2"
86
- def find(*ids)
87
- params = ids.last.is_a?(Hash) ? ids.pop : {}
88
- results = ids.flatten.compact.uniq.map do |id|
89
- resource = nil
90
- request(params.merge(:_method => method_for(:find), :_path => build_request_path(params.merge(primary_key => id)))) do |parsed_data, response|
91
- if response.success?
92
- resource = new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:metadata], :_errors => parsed_data[:errors])
93
- resource.run_callbacks :find
94
- else
95
- return nil
96
- end
97
- end
98
- resource
99
- end
100
-
101
- if ids.length > 1 || ids.first.kind_of?(Array)
102
- results
103
- else
104
- results.first
105
- end
106
- end
107
-
108
77
  # Create a new chainable scope
109
78
  #
110
79
  # @example
@@ -152,7 +121,7 @@ module Her
152
121
  end
153
122
 
154
123
  # Delegate the following methods to `scoped`
155
- [:all, :where, :create, :build, :first_or_create, :first_or_initialize].each do |method|
124
+ [:all, :where, :create, :build, :find, :first_or_create, :first_or_initialize].each do |method|
156
125
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
157
126
  def #{method}(*params)
158
127
  scoped.send(#{method.to_sym.inspect}, *params)
@@ -73,6 +73,40 @@ module Her
73
73
  end
74
74
  end
75
75
 
76
+ # Fetch specific resource(s) by their ID
77
+ #
78
+ # @example
79
+ # @user = User.find(1)
80
+ # # Fetched via GET "/users/1"
81
+ #
82
+ # @example
83
+ # @users = User.find([1, 2])
84
+ # # Fetched via GET "/users/1" and GET "/users/2"
85
+ def find(*ids)
86
+ params = @params.merge(ids.last.is_a?(Hash) ? ids.pop : {})
87
+
88
+ results = ids.flatten.compact.uniq.map do |id|
89
+ resource = nil
90
+ request_params = params.merge(
91
+ :_method => @parent.method_for(:find),
92
+ :_path => @parent.build_request_path(params.merge(@parent.primary_key => id))
93
+ )
94
+
95
+ @parent.request(request_params) do |parsed_data, response|
96
+ if response.success?
97
+ resource = @parent.new_from_parsed_data(parsed_data)
98
+ resource.run_callbacks :find
99
+ else
100
+ return nil
101
+ end
102
+ end
103
+
104
+ resource
105
+ end
106
+
107
+ ids.length > 1 || ids.first.kind_of?(Array) ? results : results.first
108
+ end
109
+
76
110
  # Create a resource and return it
77
111
  #
78
112
  # @example
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.6.4"
2
+ VERSION = "0.6.5"
3
3
  end
@@ -139,6 +139,13 @@ describe Her::Model::Attributes do
139
139
 
140
140
  context "handling metadata and errors" do
141
141
  before do
142
+ Her::API.setup :url => "https://api.example.com" do |builder|
143
+ builder.use Her::Middleware::FirstLevelParseJSON
144
+ builder.adapter :test do |stub|
145
+ stub.post("/users") { |env| [200, {}, { :id => 1, :fullname => "Tobias Fünke" }.to_json] }
146
+ end
147
+ end
148
+
142
149
  spawn_model 'Foo::User' do
143
150
  store_response_errors :errors
144
151
  store_metadata :my_data
@@ -162,6 +169,14 @@ describe Her::Model::Attributes do
162
169
  it "should remove the default method for metadata" do
163
170
  expect { @user.metadata }.to raise_error(NoMethodError)
164
171
  end
172
+
173
+ it "should work with #save" do
174
+ @user.assign_attributes(:fullname => "Tobias Fünke")
175
+ @user.save
176
+ expect { @user.metadata }.to raise_error(NoMethodError)
177
+ @user.my_data.should be_empty
178
+ @user.errors.should be_empty
179
+ end
165
180
  end
166
181
 
167
182
  context "overwriting default attribute methods" do
@@ -9,7 +9,9 @@ describe "Her::Model and ActiveModel::Dirty" do
9
9
  builder.use Faraday::Request::UrlEncoded
10
10
  builder.adapter :test do |stub|
11
11
  stub.get("/users/1") { |env| [200, {}, { :id => 1, :fullname => "Lindsay Fünke" }.to_json] }
12
+ stub.get("/users/2") { |env| [200, {}, { :id => 2, :fullname => "Maeby Fünke" }.to_json] }
12
13
  stub.put("/users/1") { |env| [200, {}, { :id => 1, :fullname => "Tobias Fünke" }.to_json] }
14
+ stub.put("/users/2") { |env| [400, {}, { :errors => ["Email cannot be blank"] }.to_json] }
13
15
  stub.post("/users") { |env| [200, {}, { :id => 1, :fullname => "Tobias Fünke" }.to_json] }
14
16
  end
15
17
  end
@@ -20,14 +22,28 @@ describe "Her::Model and ActiveModel::Dirty" do
20
22
  end
21
23
 
22
24
  context "for existing resource" do
23
- it "tracks dirty attributes" do
24
- user = Foo::User.find(1)
25
- user.fullname = "Tobias Fünke"
26
- user.fullname_changed?.should be_true
27
- user.email_changed?.should be_false
28
- user.should be_changed
29
- user.save
30
- user.should_not be_changed
25
+ context "with successful save" do
26
+ it "tracks dirty attributes" do
27
+ user = Foo::User.find(1)
28
+ user.fullname = "Tobias Fünke"
29
+ user.fullname_changed?.should be_true
30
+ user.email_changed?.should be_false
31
+ user.should be_changed
32
+ user.save
33
+ user.should_not be_changed
34
+ end
35
+ end
36
+
37
+ context "with erroneous save" do
38
+ it "tracks dirty attributes" do
39
+ user = Foo::User.find(2)
40
+ user.fullname = "Tobias Fünke"
41
+ user.fullname_changed?.should be_true
42
+ user.email_changed?.should be_false
43
+ user.should be_changed
44
+ user.save
45
+ user.should be_changed
46
+ end
31
47
  end
32
48
  end
33
49
 
@@ -190,6 +190,13 @@ describe Her::Model::Paths do
190
190
  @user.id.should == 1
191
191
  @user.fullname.should == "Tobias Fünke"
192
192
  end
193
+
194
+ it "maps a single resource using a scope to a Ruby object" do
195
+ Foo::User.scope :for_organization, lambda { |o| where(:organization_id => o) }
196
+ @user = Foo::User.for_organization(2).find(1)
197
+ @user.id.should == 1
198
+ @user.fullname.should == "Tobias Fünke"
199
+ end
193
200
  end
194
201
 
195
202
  describe "fetching a collection" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: her
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rémi Prévost
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-26 00:00:00.000000000 Z
11
+ date: 2013-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake