her 0.6.4 → 0.6.5
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 +8 -8
- data/README.md +18 -1
- data/lib/her/model/attributes.rb +8 -1
- data/lib/her/model/orm.rb +7 -38
- data/lib/her/model/relation.rb +34 -0
- data/lib/her/version.rb +1 -1
- data/spec/model/attributes_spec.rb +15 -0
- data/spec/model/dirty_spec.rb +24 -8
- data/spec/model/paths_spec.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZGIzMGM1MTY2YmRmZjZjNmJhNzhhOGQ0YjcxZmMxZDM3MTJlNWVlZg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NTM0Y2JjYWZiNjAxOTJhMTUyZjc0OTYwZjU1YTRkNGViOWM4MTcwZA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTExZDExMjk5ODU5MmQ1Nzg4YmIwNWEyYmJmZDRiMTFiMjdlNTkwNjViNzQw
|
10
|
+
YjcxN2MyM2Q2ODlmZmNkODk0OTQyOGUwY2ViMWUwMTViMWI2OTMxYWVmZjNk
|
11
|
+
NzQ0MzhiY2JlZGE2YWY4NzIyMTg1YWVhYjgwNTNhYjkzYzVjNjY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
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)
|
data/lib/her/model/attributes.rb
CHANGED
@@ -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
|
|
data/lib/her/model/orm.rb
CHANGED
@@ -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
|
-
|
46
|
-
|
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? ||
|
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
|
-
|
69
|
-
|
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)
|
data/lib/her/model/relation.rb
CHANGED
@@ -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
|
data/lib/her/version.rb
CHANGED
@@ -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
|
data/spec/model/dirty_spec.rb
CHANGED
@@ -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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
|
data/spec/model/paths_spec.rb
CHANGED
@@ -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
|
+
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-
|
11
|
+
date: 2013-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|