her 0.8.2 → 0.9.0

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/.rubocop.yml +1291 -0
  4. data/.travis.yml +2 -0
  5. data/README.md +23 -3
  6. data/her.gemspec +1 -3
  7. data/lib/her/middleware/json_api_parser.rb +1 -1
  8. data/lib/her/model/associations/association.rb +31 -0
  9. data/lib/her/model/associations/association_proxy.rb +1 -1
  10. data/lib/her/model/attributes.rb +2 -0
  11. data/lib/her/model/orm.rb +79 -6
  12. data/lib/her/model/parse.rb +8 -12
  13. data/lib/her/model/relation.rb +45 -1
  14. data/lib/her/version.rb +1 -1
  15. data/spec/api_spec.rb +34 -31
  16. data/spec/collection_spec.rb +25 -10
  17. data/spec/json_api/model_spec.rb +75 -72
  18. data/spec/middleware/accept_json_spec.rb +1 -1
  19. data/spec/middleware/first_level_parse_json_spec.rb +20 -20
  20. data/spec/middleware/json_api_parser_spec.rb +26 -7
  21. data/spec/middleware/second_level_parse_json_spec.rb +8 -9
  22. data/spec/model/associations/association_proxy_spec.rb +2 -5
  23. data/spec/model/associations_spec.rb +248 -161
  24. data/spec/model/attributes_spec.rb +106 -99
  25. data/spec/model/callbacks_spec.rb +58 -26
  26. data/spec/model/dirty_spec.rb +30 -29
  27. data/spec/model/http_spec.rb +67 -35
  28. data/spec/model/introspection_spec.rb +26 -22
  29. data/spec/model/nested_attributes_spec.rb +31 -31
  30. data/spec/model/orm_spec.rb +312 -155
  31. data/spec/model/parse_spec.rb +77 -77
  32. data/spec/model/paths_spec.rb +109 -109
  33. data/spec/model/relation_spec.rb +76 -68
  34. data/spec/model/validations_spec.rb +6 -6
  35. data/spec/model_spec.rb +17 -17
  36. data/spec/spec_helper.rb +2 -3
  37. data/spec/support/macros/model_macros.rb +2 -2
  38. metadata +32 -59
data/.travis.yml CHANGED
@@ -3,6 +3,8 @@ language: ruby
3
3
  sudo: false
4
4
 
5
5
  rvm:
6
+ - 2.4.1
7
+ - 2.3.1
6
8
  - 2.2.2
7
9
  - 2.1.6
8
10
  - 2.0.0
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Maintenance Update 29th Sept 2016
2
+
2
3
  Hi folks, [@edtjones](https://github.com/edtjones) here. Rémi has handed me the keys to Her and [@foxpaul](https://github.com/foxpaul) and I will be trying to do the library justice with the help of the community. There's loads to do; we'll get in touch with everyone who's raised a PR as soon as possible and figure out a plan of action.
3
4
 
4
5
  # Rails 5 support
@@ -15,6 +16,7 @@ If you need Rails 5 support, version 0.8.2 is for you!
15
16
  <a href="https://codeclimate.com/github/remiprev/her"><img src="http://img.shields.io/codeclimate/github/remiprev/her.svg" /></a>
16
17
  <a href='https://gemnasium.com/remiprev/her'><img src="http://img.shields.io/gemnasium/remiprev/her.svg" /></a>
17
18
  <a href="https://travis-ci.org/remiprev/her"><img src="http://img.shields.io/travis/remiprev/her/master.svg" /></a>
19
+ <a href="https://gitter.im/her-orm/Lobby"><img src="https://badges.gitter.im/her-orm/Lobby.png" alt="Gitter chat" title="" data-pin-nopin="true"></a>
18
20
  </p>
19
21
 
20
22
  ---
@@ -173,6 +175,24 @@ end
173
175
 
174
176
  Now, each HTTP request made by Her will have the `X-API-Token` header.
175
177
 
178
+ ### Basic Http Authentication
179
+ Her can use basic http auth by adding a line to your initializer
180
+
181
+ ```ruby
182
+ # config/initializers/her.rb
183
+ Her::API.setup url: "https://api.example.com" do |c|
184
+ # Request
185
+ c.use Faraday::Request::BasicAuthentication, 'myusername', 'mypassword'
186
+ c.use Faraday::Request::UrlEncoded
187
+
188
+ # Response
189
+ c.use Her::Middleware::DefaultParseJSON
190
+
191
+ # Adapter
192
+ c.use Faraday::Adapter::NetHttp
193
+ end
194
+ ```
195
+
176
196
  ### OAuth
177
197
 
178
198
  Using the `faraday_middleware` and `simple_oauth` gems, it’s fairly easy to use OAuth authentication with Her.
@@ -397,8 +417,8 @@ You can use the association methods to build new objects and save them.
397
417
  @user.comments.build(body: "Just a draft")
398
418
  # => [#<Comment body="Just a draft" user_id=1>]
399
419
 
400
- @user.comments.create(body: "Hello world.")
401
- # POST "/users/1/comments" with `body=Hello+world.`
420
+ @user.comments.create(body: "Hello world.", user_id: 1)
421
+ # POST "/comments" with `body=Hello+world.&user_id=1`
402
422
  # => [#<Comment id=3 body="Hello world." user_id=1>]
403
423
  ```
404
424
 
@@ -593,7 +613,7 @@ users = Users.all
593
613
  #### JSON API support
594
614
 
595
615
  To consume a JSON API 1.0 compliant service, it must return data in accordance with the [JSON API spec](http://jsonapi.org/). The general format
596
- of the data is as follows:
616
+ of the data is as follows:
597
617
 
598
618
  ```json
599
619
  { "data": {
data/her.gemspec CHANGED
@@ -18,9 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.require_paths = ["lib"]
19
19
 
20
20
  s.add_development_dependency "rake", "~> 10.0"
21
- s.add_development_dependency "rspec", "~> 2.13"
22
- s.add_development_dependency "rspec-its", "~> 1.0"
23
- s.add_development_dependency "fivemat", "~> 1.2"
21
+ s.add_development_dependency "rspec", "~> 3.5"
24
22
  s.add_development_dependency "json", "~> 1.8"
25
23
 
26
24
  s.add_runtime_dependency "activemodel", ">= 3.0.0", "<= 6.0.0"
@@ -25,7 +25,7 @@ module Her
25
25
  # @private
26
26
  def on_complete(env)
27
27
  env[:body] = case env[:status]
28
- when 204
28
+ when 204, 304
29
29
  parse('{}')
30
30
  else
31
31
  parse(env[:body])
@@ -49,6 +49,7 @@ module Her
49
49
 
50
50
  return @cached_result unless @params.any? || @cached_result.nil?
51
51
  return @parent.attributes[@name] unless @params.any? || @parent.attributes[@name].blank?
52
+ return @opts[:default].try(:dup) if @parent.new?
52
53
 
53
54
  path = build_association_path lambda { "#{@parent.request_path(@params)}#{@opts[:path]}" }
54
55
  @klass.get(path, @params).tap do |result|
@@ -65,6 +66,13 @@ module Her
65
66
  end
66
67
  end
67
68
 
69
+ # @private
70
+ def reset
71
+ @params = {}
72
+ @cached_result = nil
73
+ @parent.attributes.delete(@name)
74
+ end
75
+
68
76
  # Add query parameters to the HTTP request performed to fetch the data
69
77
  #
70
78
  # @example
@@ -97,6 +105,29 @@ module Her
97
105
  @klass.get_resource(path, @params)
98
106
  end
99
107
 
108
+ # Refetches the association and puts the proxy back in its initial state,
109
+ # which is unloaded. Cached associations are cleared.
110
+ #
111
+ # @example
112
+ # class User
113
+ # include Her::Model
114
+ # has_many :comments
115
+ # end
116
+ #
117
+ # class Comment
118
+ # include Her::Model
119
+ # end
120
+ #
121
+ # user = User.find(1)
122
+ # user.comments = [#<Comment(comments/2) id=2 body="Hello!">]
123
+ # user.comments.first.id = "Oops"
124
+ # user.comments.reload # => [#<Comment(comments/2) id=2 body="Hello!">]
125
+ # # Fetched again via GET "/users/1/comments"
126
+ def reload
127
+ reset
128
+ fetch
129
+ end
130
+
100
131
  end
101
132
  end
102
133
  end
@@ -15,7 +15,7 @@ module Her
15
15
  end
16
16
 
17
17
  install_proxy_methods :association,
18
- :build, :create, :where, :find, :all, :assign_nested_attributes
18
+ :build, :create, :where, :find, :all, :assign_nested_attributes, :reload
19
19
 
20
20
  # @private
21
21
  def initialize(association)
@@ -25,6 +25,8 @@ module Her
25
25
 
26
26
  attributes = self.class.default_scope.apply_to(attributes)
27
27
  assign_attributes(attributes)
28
+
29
+ yield self if block_given?
28
30
  run_callbacks :initialize
29
31
  end
30
32
 
data/lib/her/model/orm.rb CHANGED
@@ -39,8 +39,8 @@ module Her
39
39
  callback = new? ? :create : :update
40
40
  method = self.class.method_for(callback)
41
41
 
42
- run_callbacks callback do
43
- run_callbacks :save do
42
+ run_callbacks :save do
43
+ run_callbacks callback do
44
44
  params = to_params
45
45
  self.class.request(to_params.merge(:_method => method, :_path => request_path)) do |parsed_data, response|
46
46
  assign_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
@@ -49,7 +49,7 @@ module Her
49
49
 
50
50
  return false if !response.success? || @response_errors.any?
51
51
  if self.changed_attributes.present?
52
- @previously_changed = self.changed_attributes.clone
52
+ @previously_changed = self.changes.clone
53
53
  self.changed_attributes.clear
54
54
  end
55
55
  end
@@ -80,12 +80,81 @@ module Her
80
80
  assign_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
81
81
  @metadata = parsed_data[:metadata]
82
82
  @response_errors = parsed_data[:errors]
83
- @destroyed = true
83
+ @destroyed = response.success?
84
84
  end
85
85
  end
86
86
  self
87
87
  end
88
88
 
89
+ # Refetches the resource
90
+ #
91
+ # This method finds the resource by its primary key (which could be
92
+ # assigned manually) and modifies the object in-place.
93
+ #
94
+ # @example
95
+ # user = User.find(1)
96
+ # # => #<User(users/1) id=1 name="Tobias Fünke">
97
+ # user.name = "Oops"
98
+ # user.reload # Fetched again via GET "/users/1"
99
+ # # => #<User(users/1) id=1 name="Tobias Fünke">
100
+ def reload(options = nil)
101
+ fresh_object = self.class.find(id)
102
+ assign_attributes(fresh_object.attributes)
103
+ self
104
+ end
105
+
106
+ # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
107
+ # if the predicate returns +true+ the attribute will become +false+. This
108
+ # method toggles directly the underlying value without calling any setter.
109
+ # Returns +self+.
110
+ #
111
+ # @example
112
+ # user = User.first
113
+ # user.admin? # => false
114
+ # user.toggle(:admin)
115
+ # user.admin? # => true
116
+ def toggle(attribute)
117
+ attributes[attribute] = !public_send("#{attribute}?")
118
+ self
119
+ end
120
+
121
+ # Wrapper around #toggle that saves the resource. Saving is subjected to
122
+ # validation checks. Returns +true+ if the record could be saved.
123
+ def toggle!(attribute)
124
+ toggle(attribute) && save
125
+ end
126
+
127
+ # Initializes +attribute+ to zero if +nil+ and adds the value passed as
128
+ # +by+ (default is 1). The increment is performed directly on the
129
+ # underlying attribute, no setter is invoked. Only makes sense for
130
+ # number-based attributes. Returns +self+.
131
+ def increment(attribute, by = 1)
132
+ attributes[attribute] ||= 0
133
+ attributes[attribute] += by
134
+ self
135
+ end
136
+
137
+ # Wrapper around #increment that saves the resource. Saving is subjected
138
+ # to validation checks. Returns +self+.
139
+ def increment!(attribute, by = 1)
140
+ increment(attribute, by) && save
141
+ self
142
+ end
143
+
144
+ # Initializes +attribute+ to zero if +nil+ and substracts the value passed as
145
+ # +by+ (default is 1). The decrement is performed directly on the
146
+ # underlying attribute, no setter is invoked. Only makes sense for
147
+ # number-based attributes. Returns +self+.
148
+ def decrement(attribute, by = 1)
149
+ increment(attribute, -by)
150
+ end
151
+
152
+ # Wrapper around #decrement that saves the resource. Saving is subjected
153
+ # to validation checks. Returns +self+.
154
+ def decrement!(attribute, by = 1)
155
+ increment!(attribute, -by)
156
+ end
157
+
89
158
  module ClassMethods
90
159
  # Create a new chainable scope
91
160
  #
@@ -134,7 +203,8 @@ module Her
134
203
  end
135
204
 
136
205
  # Delegate the following methods to `scoped`
137
- [:all, :where, :create, :build, :find, :first_or_create, :first_or_initialize].each do |method|
206
+ [:all, :where, :create, :build, :find, :find_by, :find_or_create_by,
207
+ :find_or_initialize_by, :first_or_create, :first_or_initialize].each do |method|
138
208
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
139
209
  def #{method}(*params)
140
210
  scoped.send(#{method.to_sym.inspect}, *params)
@@ -160,7 +230,10 @@ module Her
160
230
  # # Called via DELETE "/users/1"
161
231
  def destroy_existing(id, params={})
162
232
  request(params.merge(:_method => method_for(:destroy), :_path => build_request_path(params.merge(primary_key => id)))) do |parsed_data, response|
163
- new(parse(parsed_data[:data]).merge(:_destroyed => true))
233
+ data = parse(parsed_data[:data])
234
+ metadata = parsed_data[:metadata]
235
+ response_errors = parsed_data[:errors]
236
+ new(data.merge(:_destroyed => response.success?, :metadata => metadata, :response_errors => response_errors))
164
237
  end
165
238
  end
166
239
 
@@ -52,20 +52,16 @@ module Her
52
52
  end
53
53
  end
54
54
 
55
-
56
55
  # @private
57
- # TODO: Handle has_one
58
56
  def embeded_params(attributes)
59
- associations[:has_many].select { |a| attributes.include?(a[:data_key])}.compact.inject({}) do |hash, association|
60
- params = attributes[association[:data_key]].map(&:to_params)
61
- next if params.empty?
62
- if association[:class_name].constantize.include_root_in_json?
63
- root = association[:class_name].constantize.root_element
64
- hash[association[:data_key]] = params.map { |n| n[root] }
65
- else
66
- hash[association[:data_key]] = params
67
- end
68
- hash
57
+ associations.values.flatten.each_with_object({}) do |definition, hash|
58
+ value = case association = attributes[definition[:name]]
59
+ when Her::Collection, Array
60
+ association.map { |a| a.to_params }.reject(&:empty?)
61
+ when Her::Model
62
+ association.to_params
63
+ end
64
+ hash[definition[:data_key]] = value if value.present?
69
65
  end
70
66
  end
71
67
 
@@ -65,7 +65,7 @@ module Her
65
65
  # @private
66
66
  def fetch
67
67
  @_fetch ||= begin
68
- path = @parent.build_request_path(@params)
68
+ path = @parent.build_request_path(@parent.collection_path, @params)
69
69
  method = @parent.method_for(:find)
70
70
  @parent.request(@params.merge(:_method => method, :_path => path)) do |parsed_data, response|
71
71
  @parent.new_collection(parsed_data)
@@ -109,6 +109,50 @@ module Her
109
109
  ids.length > 1 || ids.first.kind_of?(Array) ? results : results.first
110
110
  end
111
111
 
112
+ # Fetch first resource with the given attributes.
113
+ #
114
+ # If no resource is found, returns <tt>nil</tt>.
115
+ #
116
+ # @example
117
+ # @user = User.find_by(name: "Tobias", age: 42)
118
+ # # Called via GET "/users?name=Tobias&age=42"
119
+ def find_by(params)
120
+ where(params).first
121
+ end
122
+
123
+ # Fetch first resource with the given attributes, or create a resource
124
+ # with the attributes if one is not found.
125
+ #
126
+ # @example
127
+ # @user = User.find_or_create_by(email: "remi@example.com")
128
+ #
129
+ # # Returns the first item in the collection if present:
130
+ # # Called via GET "/users?email=remi@example.com"
131
+ #
132
+ # # If collection is empty:
133
+ # # POST /users with `email=remi@example.com`
134
+ # @user.email # => "remi@example.com"
135
+ # @user.new? # => false
136
+ def find_or_create_by(attributes)
137
+ find_by(attributes) || create(attributes)
138
+ end
139
+
140
+ # Fetch first resource with the given attributes, or initialize a resource
141
+ # with the attributes if one is not found.
142
+ #
143
+ # @example
144
+ # @user = User.find_or_initialize_by(email: "remi@example.com")
145
+ #
146
+ # # Returns the first item in the collection if present:
147
+ # # Called via GET "/users?email=remi@example.com"
148
+ #
149
+ # # If collection is empty:
150
+ # @user.email # => "remi@example.com"
151
+ # @user.new? # => true
152
+ def find_or_initialize_by(attributes)
153
+ find_by(attributes) || build(attributes)
154
+ end
155
+
112
156
  # Create a resource and return it
113
157
  #
114
158
  # @example
data/lib/her/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.8.2"
2
+ VERSION = "0.9.0"
3
3
  end
data/spec/api_spec.rb CHANGED
@@ -8,21 +8,24 @@ describe Her::API do
8
8
  describe "#setup" do
9
9
  context "when setting custom middleware" do
10
10
  before do
11
- class Foo; end;
12
- class Bar; end;
11
+ class Foo; end
12
+ class Bar; end
13
13
 
14
- subject.setup :url => "https://api.example.com" do |connection|
14
+ subject.setup url: "https://api.example.com" do |connection|
15
15
  connection.use Foo
16
16
  connection.use Bar
17
17
  end
18
18
  end
19
19
 
20
- specify { subject.connection.builder.handlers.should == [Foo, Bar] }
20
+ specify { expect(subject.connection.builder.handlers).to eq([Foo, Bar]) }
21
21
  end
22
22
 
23
23
  context "when setting custom options" do
24
- before { subject.setup :foo => { :bar => "baz" }, :url => "https://api.example.com" }
25
- its(:options) { should == { :foo => { :bar => "baz" }, :url => "https://api.example.com" } }
24
+ before { subject.setup foo: { bar: "baz" }, url: "https://api.example.com" }
25
+
26
+ describe "#options" do
27
+ it { expect(subject.options).to eq(foo: { bar: "baz" }, url: "https://api.example.com") }
28
+ end
26
29
  end
27
30
  end
28
31
 
@@ -30,83 +33,83 @@ describe Her::API do
30
33
  before do
31
34
  class SimpleParser < Faraday::Response::Middleware
32
35
  def on_complete(env)
33
- env[:body] = { :data => env[:body] }
36
+ env[:body] = { data: env[:body] }
34
37
  end
35
38
  end
36
39
  end
37
40
 
38
41
  context "making HTTP requests" do
39
- let(:parsed_data) { subject.request(:_method => :get, :_path => "/foo")[:parsed_data] }
42
+ let(:parsed_data) { subject.request(_method: :get, _path: "/foo")[:parsed_data] }
40
43
  before do
41
- subject.setup :url => "https://api.example.com" do |builder|
44
+ subject.setup url: "https://api.example.com" do |builder|
42
45
  builder.use SimpleParser
43
- builder.adapter(:test) { |stub| stub.get("/foo") { |env| [200, {}, "Foo, it is."] } }
46
+ builder.adapter(:test) { |stub| stub.get("/foo") { [200, {}, "Foo, it is."] } }
44
47
  end
45
48
  end
46
49
 
47
- specify { parsed_data[:data].should == "Foo, it is." }
50
+ specify { expect(parsed_data[:data]).to eq("Foo, it is.") }
48
51
  end
49
52
 
50
53
  context "making HTTP requests while specifying custom HTTP headers" do
51
- let(:parsed_data) { subject.request(:_method => :get, :_path => "/foo", :_headers => { "X-Page" => 2 })[:parsed_data] }
54
+ let(:parsed_data) { subject.request(_method: :get, _path: "/foo", _headers: { "X-Page" => 2 })[:parsed_data] }
52
55
 
53
56
  before do
54
- subject.setup :url => "https://api.example.com" do |builder|
57
+ subject.setup url: "https://api.example.com" do |builder|
55
58
  builder.use SimpleParser
56
- builder.adapter(:test) { |stub| stub.get("/foo") { |env| [200, {}, "Foo, it is page #{env[:request_headers]["X-Page"]}."] } }
59
+ builder.adapter(:test) { |stub| stub.get("/foo") { |env| [200, {}, "Foo, it is page #{env[:request_headers]['X-Page']}."] } }
57
60
  end
58
61
  end
59
62
 
60
- specify { parsed_data[:data].should == "Foo, it is page 2." }
63
+ specify { expect(parsed_data[:data]).to eq("Foo, it is page 2.") }
61
64
  end
62
65
 
63
66
  context "parsing a request with the default parser" do
64
- let(:parsed_data) { subject.request(:_method => :get, :_path => "users/1")[:parsed_data] }
67
+ let(:parsed_data) { subject.request(_method: :get, _path: "users/1")[:parsed_data] }
65
68
  before do
66
- subject.setup :url => "https://api.example.com" do |builder|
69
+ subject.setup url: "https://api.example.com" do |builder|
67
70
  builder.use Her::Middleware::FirstLevelParseJSON
68
71
  builder.adapter :test do |stub|
69
- stub.get("/users/1") { |env| [200, {}, MultiJson.dump({ :id => 1, :name => "George Michael Bluth", :errors => ["This is a single error"], :metadata => { :page => 1, :per_page => 10 } })] }
72
+ stub.get("/users/1") { [200, {}, MultiJson.dump(id: 1, name: "George Michael Bluth", errors: ["This is a single error"], metadata: { page: 1, per_page: 10 })] }
70
73
  end
71
74
  end
72
75
  end
73
76
 
74
77
  specify do
75
- parsed_data[:data].should == { :id => 1, :name => "George Michael Bluth" }
76
- parsed_data[:errors].should == ["This is a single error"]
77
- parsed_data[:metadata].should == { :page => 1, :per_page => 10 }
78
+ expect(parsed_data[:data]).to eq(id: 1, name: "George Michael Bluth")
79
+ expect(parsed_data[:errors]).to eq(["This is a single error"])
80
+ expect(parsed_data[:metadata]).to eq(page: 1, per_page: 10)
78
81
  end
79
82
  end
80
83
 
81
84
  context "parsing a request with a custom parser" do
82
- let(:parsed_data) { subject.request(:_method => :get, :_path => "users/1")[:parsed_data] }
85
+ let(:parsed_data) { subject.request(_method: :get, _path: "users/1")[:parsed_data] }
83
86
  before do
84
87
  class CustomParser < Faraday::Response::Middleware
85
88
  def on_complete(env)
86
- json = MultiJson.load(env[:body], :symbolize_keys => true)
89
+ json = MultiJson.load(env[:body], symbolize_keys: true)
87
90
  errors = json.delete(:errors) || []
88
91
  metadata = json.delete(:metadata) || {}
89
92
  env[:body] = {
90
- :data => json,
91
- :errors => errors,
92
- :metadata => metadata,
93
+ data: json,
94
+ errors: errors,
95
+ metadata: metadata
93
96
  }
94
97
  end
95
98
  end
96
99
 
97
- subject.setup :url => "https://api.example.com" do |builder|
100
+ subject.setup url: "https://api.example.com" do |builder|
98
101
  builder.use CustomParser
99
102
  builder.use Faraday::Request::UrlEncoded
100
103
  builder.adapter :test do |stub|
101
- stub.get("/users/1") { |env| [200, {}, MultiJson.dump(:id => 1, :name => "George Michael Bluth")] }
104
+ stub.get("/users/1") { [200, {}, MultiJson.dump(id: 1, name: "George Michael Bluth")] }
102
105
  end
103
106
  end
104
107
  end
105
108
 
106
109
  specify do
107
- parsed_data[:data].should == { :id => 1, :name => "George Michael Bluth" }
108
- parsed_data[:errors].should == []
109
- parsed_data[:metadata].should == {}
110
+ expect(parsed_data[:data]).to eq(id: 1, name: "George Michael Bluth")
111
+ expect(parsed_data[:errors]).to eq([])
112
+ expect(parsed_data[:metadata]).to eq({})
110
113
  end
111
114
  end
112
115
  end
@@ -1,26 +1,41 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe Her::Collection do
4
-
5
4
  let(:items) { [1, 2, 3, 4] }
6
- let(:metadata) { { :name => 'Testname' } }
7
- let(:errors) { { :name => ['not_present'] } }
5
+ let(:metadata) { { name: "Testname" } }
6
+ let(:errors) { { name: ["not_present"] } }
8
7
 
9
8
  describe "#new" do
10
9
  context "without parameters" do
11
10
  subject { Her::Collection.new }
12
11
 
13
- it { should eq([]) }
14
- its(:metadata) { should eq({}) }
15
- its(:errors) { should eq({}) }
12
+ it { is_expected.to eq([]) }
13
+
14
+ describe "#metadata" do
15
+ subject { super().metadata }
16
+ it { is_expected.to eq({}) }
17
+ end
18
+
19
+ describe "#errors" do
20
+ subject { super().errors }
21
+ it { is_expected.to eq({}) }
22
+ end
16
23
  end
17
24
 
18
25
  context "with parameters" do
19
26
  subject { Her::Collection.new(items, metadata, errors) }
20
27
 
21
- it { should eq([1,2,3,4]) }
22
- its(:metadata) { should eq({ :name => 'Testname' }) }
23
- its(:errors) { should eq({ :name => ['not_present'] }) }
28
+ it { is_expected.to eq([1, 2, 3, 4]) }
29
+
30
+ describe "#metadata" do
31
+ subject { super().metadata }
32
+ it { is_expected.to eq(name: "Testname") }
33
+ end
34
+
35
+ describe "#errors" do
36
+ subject { super().errors }
37
+ it { is_expected.to eq(name: ["not_present"]) }
38
+ end
24
39
  end
25
40
  end
26
41
  end