her 0.6.7 → 0.6.8

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.
@@ -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'