her 0.6.7 → 0.6.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,14 +7,14 @@ rvm:
7
7
  - 1.8.7
8
8
 
9
9
  gemfile:
10
- - Gemfile
11
- - gemfiles/activemodel-4.0.gemfile
10
+ - gemfiles/Gemfile.activemodel-4.0
11
+ - gemfiles/Gemfile.activemodel-3.2.x
12
12
 
13
13
  matrix:
14
14
  exclude:
15
15
  - rvm: 1.8.7
16
- gemfile: gemfiles/activemodel-4.0.gemfile
16
+ gemfile: gemfiles/Gemfile.activemodel-4.0
17
17
  - rvm: 1.9.2
18
- gemfile: gemfiles/activemodel-4.0.gemfile
18
+ gemfile: gemfiles/Gemfile.activemodel-4.0
19
19
 
20
20
  script: "echo 'COME ON!' && bundle exec rake spec"
data/README.md CHANGED
@@ -534,6 +534,25 @@ article.title # => "Hello world."
534
534
 
535
535
  Of course, you can use both `include_root_in_json` and `parse_root_in_json` at the same time.
536
536
 
537
+ #### ActiveModel::Serializers support
538
+
539
+ If the API returns data in the default format used by the
540
+ [ActiveModel::Serializers](https://github.com/rails-api/active_model_serializers)
541
+ project you need to configure Her as follows:
542
+
543
+ ```ruby
544
+ class User
545
+ include Her::Model
546
+ parse_root_in_json true, format: :active_model_serializers
547
+ end
548
+
549
+ user = Users.find(1)
550
+ # GET "/users/1", response is { "user": { "id": 1, "fullname": "Lindsay Fünke"} }
551
+
552
+ users = Users.all
553
+ # GET "/users", response is { "users": [{ "id": 1, "fullname": "Lindsay Fünke"}] }
554
+ ```
555
+
537
556
  ### Custom requests
538
557
 
539
558
  You can easily define custom requests for your models using `custom_get`, `custom_post`, etc.
@@ -906,6 +925,7 @@ These [fine folks](https://github.com/remiprev/her/contributors) helped with Her
906
925
  * [@jonkarna](https://github.com/jonkarna)
907
926
  * [@aclevy](https://github.com/aclevy)
908
927
  * [@stevschmid](https://github.com/stevschmid)
928
+ * [@prognostikos](https://github.com/prognostikos)
909
929
 
910
930
  ## License
911
931
 
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec :path => "../"
4
+
5
+ gem 'activemodel', '~> 3.2.0'
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec :path => "../"
4
+
5
+ gem 'activemodel', '~> 4.0.0'
@@ -70,6 +70,22 @@ module Her
70
70
  end
71
71
  alias all where
72
72
 
73
+ # Fetches the data specified by id
74
+ #
75
+ # @example
76
+ # class User
77
+ # include Her::Model
78
+ # has_many :comments
79
+ # end
80
+ #
81
+ # user = User.find(1)
82
+ # user.comments.find(3) # Fetched via GET "/users/1/comments/3
83
+ def find(id)
84
+ return nil if id.blank?
85
+ path = build_association_path lambda { "#{@parent.request_path(@params)}#{@opts[:path]}/#{id}" }
86
+ @klass.get(path, @params)
87
+ end
88
+
73
89
  # @private
74
90
  def nil?
75
91
  fetch.nil?
@@ -32,7 +32,7 @@ module Her
32
32
  #
33
33
  # @private
34
34
  def self.initialize_collection(klass, parsed_data={})
35
- collection_data = parsed_data[:data].map do |item_data|
35
+ collection_data = klass.extract_array(parsed_data).map do |item_data|
36
36
  resource = klass.new(klass.parse(item_data))
37
37
  resource.run_callbacks :find
38
38
  resource
@@ -64,7 +64,7 @@ module Her
64
64
  path = build_request_path_from_string_or_symbol(path, params)
65
65
  params = to_params(params) unless #{method.to_sym.inspect} == :get
66
66
  send(:'#{method}_raw', path, params) do |parsed_data, response|
67
- if parsed_data[:data].is_a?(Array)
67
+ if parsed_data[:data].is_a?(Array) || active_model_serializers_format?
68
68
  new_collection(parsed_data)
69
69
  else
70
70
  new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:metadata], :_errors => parsed_data[:errors])
@@ -115,7 +115,7 @@ module Her
115
115
  # User.all # Called via GET "/users?admin=1"
116
116
  # User.new.admin # => 1
117
117
  def default_scope(block=nil)
118
- @_her_default_scope ||= superclass.respond_to?(:default_scope) ? superclass.default_scope : scoped
118
+ @_her_default_scope ||= (!respond_to?(:default_scope) && superclass.respond_to?(:default_scope)) ? superclass.default_scope : scoped
119
119
  @_her_default_scope = @_her_default_scope.instance_exec(&block) unless block.nil?
120
120
  @_her_default_scope
121
121
  end
@@ -19,7 +19,7 @@ module Her
19
19
  # @param [Hash] data
20
20
  # @private
21
21
  def parse(data)
22
- parse_root_in_json? ? data[parsed_root_element] : data
22
+ parse_root_in_json? ? data.fetch(parsed_root_element) { data } : data
23
23
  end
24
24
 
25
25
  # @private
@@ -51,13 +51,14 @@ module Her
51
51
  # include Her::Model
52
52
  # parse_root_in_json true
53
53
  # end
54
- def parse_root_in_json(value = nil)
54
+ def parse_root_in_json(value = nil, options = {})
55
55
  @_her_parse_root_in_json ||= begin
56
56
  superclass.parse_root_in_json if superclass.respond_to?(:parse_root_in_json)
57
57
  end
58
58
 
59
59
  return @_her_parse_root_in_json unless value
60
60
  @_her_parse_root_in_json = value
61
+ @_her_parse_root_in_json_format = options[:format]
61
62
  end
62
63
  alias parse_root_in_json? parse_root_in_json
63
64
 
@@ -97,6 +98,38 @@ module Her
97
98
  end
98
99
  end
99
100
 
101
+ # Extract an array from the request data
102
+ #
103
+ # @example
104
+ # # with parse_root_in_json true, :format => :active_model_serializers
105
+ # class User
106
+ # include Her::Model
107
+ # parse_root_in_json true, :format => :active_model_serializers
108
+ # end
109
+ #
110
+ # users = User.all # { :users => [ { :id => 1, :name => "Tobias" } ] }
111
+ # users.first.name # => "Tobias"
112
+ #
113
+ # # without parse_root_in_json
114
+ # class User
115
+ # include Her::Model
116
+ # end
117
+ #
118
+ # users = User.all # [ { :id => 1, :name => "Tobias" } ]
119
+ # users.first.name # => "Tobias"
120
+ def extract_array(request_data)
121
+ if active_model_serializers_format?
122
+ request_data[:data][pluralized_parsed_root_element]
123
+ else
124
+ request_data[:data]
125
+ end
126
+ end
127
+
128
+ # @private
129
+ def pluralized_parsed_root_element
130
+ parsed_root_element.to_s.pluralize.to_sym
131
+ end
132
+
100
133
  # @private
101
134
  def included_root_element
102
135
  include_root_in_json == true ? root_element : include_root_in_json
@@ -106,6 +139,11 @@ module Her
106
139
  def parsed_root_element
107
140
  parse_root_in_json == true ? root_element : parse_root_in_json
108
141
  end
142
+
143
+ # @private
144
+ def active_model_serializers_format?
145
+ @_her_parse_root_in_json_format == :active_model_serializers
146
+ end
109
147
  end
110
148
  end
111
149
  end
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.6.7"
2
+ VERSION = "0.6.8"
3
3
  end
@@ -91,6 +91,7 @@ describe Her::Model::Associations do
91
91
  stub.get("/users/2") { |env| [200, {}, { :id => 2, :name => "Lindsay Fünke", :organization_id => 2 }.to_json] }
92
92
  stub.get("/users/1/comments") { |env| [200, {}, [{ :comment => { :id => 4, :body => "They're having a FIRESALE?" } }].to_json] }
93
93
  stub.get("/users/2/comments") { |env| [200, {}, [{ :comment => { :id => 4, :body => "They're having a FIRESALE?" } }, { :comment => { :id => 5, :body => "Is this the tiny town from Footloose?" } }].to_json] }
94
+ stub.get("/users/2/comments/5") { |env| [200, {}, { :comment => { :id => 5, :body => "Is this the tiny town from Footloose?" } }.to_json] }
94
95
  stub.get("/users/2/role") { |env| [200, {}, { :id => 2, :body => "User" }.to_json] }
95
96
  stub.get("/users/1/role") { |env| [200, {}, { :id => 3, :body => "User" }.to_json] }
96
97
  stub.get("/users/1/posts") { |env| [200, {}, [{:id => 1, :body => 'blogging stuff', :admin_id => 1 }].to_json] }
@@ -211,6 +212,11 @@ describe Her::Model::Associations do
211
212
  @user_without_included_data.organization.name.should == "Bluth Company"
212
213
  end
213
214
 
215
+ it "fetches data with the specified id when calling find" do
216
+ comment = @user_without_included_data.comments.find(5)
217
+ comment.id.should eq(5)
218
+ end
219
+
214
220
  [:create, :save_existing, :destroy].each do |type|
215
221
  context "after #{type}" do
216
222
  let(:subject) { self.send("user_with_included_data_after_#{type}")}
@@ -150,6 +150,50 @@ describe Her::Model::Parse do
150
150
  @new_user.fullname.should == "Lindsay Fünke"
151
151
  end
152
152
  end
153
+
154
+ context "to true with :format => :active_model_serializers" do
155
+ before do
156
+ Her::API.default_api.connection.adapter :test do |stub|
157
+ stub.post("/users") { |env| [200, {}, { :user => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json] }
158
+ stub.get("/users") { |env| [200, {}, { :users => [ { :id => 1, :fullname => "Lindsay Fünke" } ] }.to_json] }
159
+ stub.get("/users/admins") { |env| [200, {}, { :users => [ { :id => 1, :fullname => "Lindsay Fünke" } ] }.to_json] }
160
+ stub.get("/users/1") { |env| [200, {}, { :user => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json] }
161
+ stub.put("/users/1") { |env| [200, {}, { :user => { :id => 1, :fullname => "Tobias Fünke Jr." } }.to_json] }
162
+ end
163
+
164
+ spawn_model("Foo::User") do
165
+ parse_root_in_json true, :format => :active_model_serializers
166
+ custom_get :admins
167
+ end
168
+ end
169
+
170
+ it "parse the data from the JSON root element after .create" do
171
+ @new_user = Foo::User.create(:fullname => "Lindsay Fünke")
172
+ @new_user.fullname.should == "Lindsay Fünke"
173
+ end
174
+
175
+ it "parse the data from the JSON root element after an arbitrary HTTP request" do
176
+ @users = Foo::User.admins
177
+ @users.first.fullname.should == "Lindsay Fünke"
178
+ end
179
+
180
+ it "parse the data from the JSON root element after .all" do
181
+ @users = Foo::User.all
182
+ @users.first.fullname.should == "Lindsay Fünke"
183
+ end
184
+
185
+ it "parse the data from the JSON root element after .find" do
186
+ @user = Foo::User.find(1)
187
+ @user.fullname.should == "Lindsay Fünke"
188
+ end
189
+
190
+ it "parse the data from the JSON root element after .save" do
191
+ @user = Foo::User.find(1)
192
+ @user.fullname = "Tobias Fünke"
193
+ @user.save
194
+ @user.fullname.should == "Tobias Fünke Jr."
195
+ end
196
+ end
153
197
  end
154
198
 
155
199
  context "when to_params is set" do
@@ -125,6 +125,28 @@ describe Her::Model::Paths do
125
125
  end
126
126
  end
127
127
 
128
+ context "children model" do
129
+ before do
130
+ Her::API.setup :url => "https://api.example.com" do |builder|
131
+ builder.use Her::Middleware::FirstLevelParseJSON
132
+ builder.use Faraday::Request::UrlEncoded
133
+ builder.adapter :test do |stub|
134
+ stub.get("/users/foo") { |env| [200, {}, { :id => 'foo' }.to_json] }
135
+ end
136
+ end
137
+
138
+ spawn_model("Foo::Model") { include_root_in_json true }
139
+
140
+ class User < Foo::Model; end
141
+ @spawned_models << :User
142
+ end
143
+
144
+ it "builds path using the children model name" do
145
+ User.find('foo').id.should == 'foo'
146
+ User.find('foo').id.should == 'foo'
147
+ end
148
+ end
149
+
128
150
  context "nested model" do
129
151
  before do
130
152
  spawn_model "Foo::User"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: her
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.7
4
+ version: 0.6.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-27 00:00:00.000000000 Z
12
+ date: 2013-07-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -156,7 +156,8 @@ files:
156
156
  - README.md
157
157
  - Rakefile
158
158
  - UPGRADE.md
159
- - gemfiles/activemodel-4.0.gemfile
159
+ - gemfiles/Gemfile.activemodel-3.2.x
160
+ - gemfiles/Gemfile.activemodel-4.0
160
161
  - her.gemspec
161
162
  - lib/her.rb
162
163
  - lib/her/api.rb
@@ -223,7 +224,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
223
224
  version: '0'
224
225
  segments:
225
226
  - 0
226
- hash: 1578317715926145011
227
+ hash: 2536489429371279776
227
228
  required_rubygems_version: !ruby/object:Gem::Requirement
228
229
  none: false
229
230
  requirements:
@@ -232,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
232
233
  version: '0'
233
234
  segments:
234
235
  - 0
235
- hash: 1578317715926145011
236
+ hash: 2536489429371279776
236
237
  requirements: []
237
238
  rubyforge_project:
238
239
  rubygems_version: 1.8.23
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gemspec path: "../"
4
-
5
- gem 'activemodel', '~> 4.0.0.rc1'