her 0.8.2 → 0.10.4
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 +4 -4
- data/.rspec +1 -1
- data/.rubocop.yml +1291 -0
- data/.travis.yml +6 -1
- data/README.md +29 -11
- data/her.gemspec +3 -5
- data/lib/her/api.rb +16 -9
- data/lib/her/middleware/json_api_parser.rb +1 -1
- data/lib/her/model/associations/association.rb +32 -5
- data/lib/her/model/associations/association_proxy.rb +1 -1
- data/lib/her/model/associations/belongs_to_association.rb +1 -1
- data/lib/her/model/associations/has_many_association.rb +3 -3
- data/lib/her/model/attributes.rb +105 -75
- data/lib/her/model/http.rb +3 -3
- data/lib/her/model/introspection.rb +1 -1
- data/lib/her/model/orm.rb +96 -19
- data/lib/her/model/parse.rb +27 -17
- data/lib/her/model/relation.rb +46 -2
- data/lib/her/version.rb +1 -1
- data/spec/api_spec.rb +34 -31
- data/spec/collection_spec.rb +25 -10
- data/spec/json_api/model_spec.rb +75 -72
- data/spec/middleware/accept_json_spec.rb +1 -1
- data/spec/middleware/first_level_parse_json_spec.rb +20 -20
- data/spec/middleware/json_api_parser_spec.rb +26 -7
- data/spec/middleware/second_level_parse_json_spec.rb +8 -9
- data/spec/model/associations/association_proxy_spec.rb +2 -5
- data/spec/model/associations_spec.rb +617 -295
- data/spec/model/attributes_spec.rb +114 -107
- data/spec/model/callbacks_spec.rb +59 -27
- data/spec/model/dirty_spec.rb +70 -29
- data/spec/model/http_spec.rb +67 -35
- data/spec/model/introspection_spec.rb +26 -22
- data/spec/model/nested_attributes_spec.rb +31 -31
- data/spec/model/orm_spec.rb +332 -157
- data/spec/model/parse_spec.rb +250 -77
- data/spec/model/paths_spec.rb +109 -109
- data/spec/model/relation_spec.rb +89 -69
- data/spec/model/validations_spec.rb +6 -6
- data/spec/model_spec.rb +17 -17
- data/spec/spec_helper.rb +2 -3
- data/spec/support/macros/model_macros.rb +2 -2
- metadata +36 -63
data/lib/her/model/orm.rb
CHANGED
@@ -39,17 +39,13 @@ module Her
|
|
39
39
|
callback = new? ? :create : :update
|
40
40
|
method = self.class.method_for(callback)
|
41
41
|
|
42
|
-
run_callbacks
|
43
|
-
run_callbacks
|
44
|
-
params = to_params
|
42
|
+
run_callbacks :save do
|
43
|
+
run_callbacks callback do
|
45
44
|
self.class.request(to_params.merge(:_method => method, :_path => request_path)) do |parsed_data, response|
|
46
|
-
|
47
|
-
@metadata = parsed_data[:metadata]
|
48
|
-
@response_errors = parsed_data[:errors]
|
49
|
-
|
45
|
+
load_from_parsed_data(parsed_data)
|
50
46
|
return false if !response.success? || @response_errors.any?
|
51
47
|
if self.changed_attributes.present?
|
52
|
-
@previously_changed = self.
|
48
|
+
@previously_changed = self.changes.clone
|
53
49
|
self.changed_attributes.clear
|
54
50
|
end
|
55
51
|
end
|
@@ -77,15 +73,92 @@ module Her
|
|
77
73
|
method = self.class.method_for(:destroy)
|
78
74
|
run_callbacks :destroy do
|
79
75
|
self.class.request(params.merge(:_method => method, :_path => request_path)) do |parsed_data, response|
|
80
|
-
|
81
|
-
@
|
82
|
-
@response_errors = parsed_data[:errors]
|
83
|
-
@destroyed = true
|
76
|
+
load_from_parsed_data(parsed_data)
|
77
|
+
@destroyed = response.success?
|
84
78
|
end
|
85
79
|
end
|
86
80
|
self
|
87
81
|
end
|
88
82
|
|
83
|
+
# Initializes +attribute+ to zero if +nil+ and adds the value passed as
|
84
|
+
# +by+ (default is 1). The increment is performed directly on the
|
85
|
+
# underlying attribute, no setter is invoked. Only makes sense for
|
86
|
+
# number-based attributes. Returns +self+.
|
87
|
+
def increment(attribute, by = 1)
|
88
|
+
attributes[attribute] ||= 0
|
89
|
+
attributes[attribute] += by
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
# Wrapper around #increment that saves the resource. Saving is subjected
|
94
|
+
# to validation checks. Returns +self+.
|
95
|
+
def increment!(attribute, by = 1)
|
96
|
+
increment(attribute, by) && save
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
# Initializes +attribute+ to zero if +nil+ and substracts the value passed as
|
101
|
+
# +by+ (default is 1). The decrement is performed directly on the
|
102
|
+
# underlying attribute, no setter is invoked. Only makes sense for
|
103
|
+
# number-based attributes. Returns +self+.
|
104
|
+
def decrement(attribute, by = 1)
|
105
|
+
increment(attribute, -by)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Wrapper around #decrement that saves the resource. Saving is subjected
|
109
|
+
# to validation checks. Returns +self+.
|
110
|
+
def decrement!(attribute, by = 1)
|
111
|
+
increment!(attribute, -by)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
|
115
|
+
# if the predicate returns +true+ the attribute will become +false+. This
|
116
|
+
# method toggles directly the underlying value without calling any setter.
|
117
|
+
# Returns +self+.
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# user = User.first
|
121
|
+
# user.admin? # => false
|
122
|
+
# user.toggle(:admin)
|
123
|
+
# user.admin? # => true
|
124
|
+
def toggle(attribute)
|
125
|
+
attributes[attribute] = !public_send("#{attribute}?")
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
# Wrapper around #toggle that saves the resource. Saving is subjected to
|
130
|
+
# validation checks. Returns +true+ if the record could be saved.
|
131
|
+
def toggle!(attribute)
|
132
|
+
toggle(attribute) && save
|
133
|
+
end
|
134
|
+
|
135
|
+
# Refetches the resource
|
136
|
+
#
|
137
|
+
# This method finds the resource by its primary key (which could be
|
138
|
+
# assigned manually) and modifies the object in-place.
|
139
|
+
#
|
140
|
+
# @example
|
141
|
+
# user = User.find(1)
|
142
|
+
# # => #<User(users/1) id=1 name="Tobias Fünke">
|
143
|
+
# user.name = "Oops"
|
144
|
+
# user.reload # Fetched again via GET "/users/1"
|
145
|
+
# # => #<User(users/1) id=1 name="Tobias Fünke">
|
146
|
+
def reload(options = nil)
|
147
|
+
fresh_object = self.class.find(id)
|
148
|
+
assign_attributes(fresh_object.attributes)
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
# Uses parsed response to assign attributes and metadata
|
153
|
+
#
|
154
|
+
# @private
|
155
|
+
def load_from_parsed_data(parsed_data)
|
156
|
+
data = parsed_data[:data]
|
157
|
+
assign_attributes(self.class.parse(data)) if data.any?
|
158
|
+
@metadata = parsed_data[:metadata]
|
159
|
+
@response_errors = parsed_data[:errors]
|
160
|
+
end
|
161
|
+
|
89
162
|
module ClassMethods
|
90
163
|
# Create a new chainable scope
|
91
164
|
#
|
@@ -105,10 +178,8 @@ module Her
|
|
105
178
|
instance_exec(*args, &code)
|
106
179
|
end
|
107
180
|
|
108
|
-
# Add the scope method to the
|
109
|
-
|
110
|
-
define_method(name) { |*args| instance_exec(*args, &code) }
|
111
|
-
end
|
181
|
+
# Add the scope method to the default/blank relation
|
182
|
+
scoped.define_singleton_method(name) { |*args| instance_exec(*args, &code) }
|
112
183
|
end
|
113
184
|
|
114
185
|
# @private
|
@@ -134,7 +205,8 @@ module Her
|
|
134
205
|
end
|
135
206
|
|
136
207
|
# Delegate the following methods to `scoped`
|
137
|
-
[:all, :where, :create, :build, :find, :
|
208
|
+
[:all, :where, :create, :build, :find, :find_by, :find_or_create_by,
|
209
|
+
:find_or_initialize_by, :first_or_create, :first_or_initialize].each do |method|
|
138
210
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
139
211
|
def #{method}(*params)
|
140
212
|
scoped.send(#{method.to_sym.inspect}, *params)
|
@@ -160,7 +232,12 @@ module Her
|
|
160
232
|
# # Called via DELETE "/users/1"
|
161
233
|
def destroy_existing(id, params={})
|
162
234
|
request(params.merge(:_method => method_for(:destroy), :_path => build_request_path(params.merge(primary_key => id)))) do |parsed_data, response|
|
163
|
-
|
235
|
+
data = parse(parsed_data[:data])
|
236
|
+
metadata = parsed_data[:metadata]
|
237
|
+
response_errors = parsed_data[:errors]
|
238
|
+
record = new(data.merge(:_destroyed => response.success?, :metadata => metadata))
|
239
|
+
record.response_errors = response_errors
|
240
|
+
record
|
164
241
|
end
|
165
242
|
end
|
166
243
|
|
@@ -196,9 +273,9 @@ module Her
|
|
196
273
|
resource
|
197
274
|
end
|
198
275
|
|
199
|
-
private
|
200
276
|
# @private
|
201
277
|
def blank_relation
|
278
|
+
@blank_relation ||= superclass.blank_relation.clone.tap { |r| r.parent = self } if superclass.respond_to?(:blank_relation)
|
202
279
|
@blank_relation ||= Relation.new(self)
|
203
280
|
end
|
204
281
|
end
|
data/lib/her/model/parse.rb
CHANGED
@@ -32,8 +32,18 @@ module Her
|
|
32
32
|
|
33
33
|
# @private
|
34
34
|
def to_params(attributes, changes={})
|
35
|
-
filtered_attributes = attributes.
|
35
|
+
filtered_attributes = attributes.each_with_object({}) do |(key, value), memo|
|
36
|
+
case value
|
37
|
+
when Her::Model
|
38
|
+
when ActiveModel::Serialization
|
39
|
+
value = value.serializable_hash.symbolize_keys
|
40
|
+
end
|
41
|
+
|
42
|
+
memo[key.to_sym] = value
|
43
|
+
end
|
44
|
+
|
36
45
|
filtered_attributes.merge!(embeded_params(attributes))
|
46
|
+
|
37
47
|
if her_api.options[:send_only_modified_attributes]
|
38
48
|
filtered_attributes = changes.symbolize_keys.keys.inject({}) do |hash, attribute|
|
39
49
|
hash[attribute] = filtered_attributes[attribute]
|
@@ -52,20 +62,16 @@ module Her
|
|
52
62
|
end
|
53
63
|
end
|
54
64
|
|
55
|
-
|
56
65
|
# @private
|
57
|
-
# TODO: Handle has_one
|
58
66
|
def embeded_params(attributes)
|
59
|
-
associations
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
hash
|
67
|
+
associations.values.flatten.each_with_object({}) do |definition, hash|
|
68
|
+
value = case association = attributes[definition[:name]]
|
69
|
+
when Her::Collection, Array
|
70
|
+
association.map { |a| a.to_params }.reject(&:empty?)
|
71
|
+
when Her::Model
|
72
|
+
association.to_params
|
73
|
+
end
|
74
|
+
hash[definition[:data_key]] = value if value.present?
|
69
75
|
end
|
70
76
|
end
|
71
77
|
|
@@ -139,7 +145,8 @@ module Her
|
|
139
145
|
|
140
146
|
# @private
|
141
147
|
def root_element_included?(data)
|
142
|
-
data
|
148
|
+
element = data[parsed_root_element]
|
149
|
+
element.is_a?(Hash) || element.is_a?(Array)
|
143
150
|
end
|
144
151
|
|
145
152
|
# @private
|
@@ -198,17 +205,20 @@ module Her
|
|
198
205
|
|
199
206
|
# @private
|
200
207
|
def request_new_object_on_build?
|
201
|
-
@_her_request_new_object_on_build
|
208
|
+
return @_her_request_new_object_on_build unless @_her_request_new_object_on_build.nil?
|
209
|
+
superclass.respond_to?(:request_new_object_on_build?) && superclass.request_new_object_on_build?
|
202
210
|
end
|
203
211
|
|
204
212
|
# @private
|
205
213
|
def include_root_in_json?
|
206
|
-
@_her_include_root_in_json
|
214
|
+
return @_her_include_root_in_json unless @_her_include_root_in_json.nil?
|
215
|
+
superclass.respond_to?(:include_root_in_json?) && superclass.include_root_in_json?
|
207
216
|
end
|
208
217
|
|
209
218
|
# @private
|
210
219
|
def parse_root_in_json?
|
211
|
-
@_her_parse_root_in_json
|
220
|
+
return @_her_parse_root_in_json unless @_her_parse_root_in_json.nil?
|
221
|
+
superclass.respond_to?(:parse_root_in_json?) && superclass.parse_root_in_json?
|
212
222
|
end
|
213
223
|
end
|
214
224
|
end
|
data/lib/her/model/relation.rb
CHANGED
@@ -3,6 +3,7 @@ module Her
|
|
3
3
|
class Relation
|
4
4
|
# @private
|
5
5
|
attr_accessor :params
|
6
|
+
attr_writer :parent
|
6
7
|
|
7
8
|
# @private
|
8
9
|
def initialize(parent)
|
@@ -65,7 +66,7 @@ module Her
|
|
65
66
|
# @private
|
66
67
|
def fetch
|
67
68
|
@_fetch ||= begin
|
68
|
-
path = @parent.build_request_path(@params)
|
69
|
+
path = @parent.build_request_path(@parent.collection_path, @params)
|
69
70
|
method = @parent.method_for(:find)
|
70
71
|
@parent.request(@params.merge(:_method => method, :_path => path)) do |parsed_data, response|
|
71
72
|
@parent.new_collection(parsed_data)
|
@@ -96,7 +97,6 @@ module Her
|
|
96
97
|
@parent.request(request_params) do |parsed_data, response|
|
97
98
|
if response.success?
|
98
99
|
resource = @parent.new_from_parsed_data(parsed_data)
|
99
|
-
resource.instance_variable_set(:@changed_attributes, {})
|
100
100
|
resource.run_callbacks :find
|
101
101
|
else
|
102
102
|
return nil
|
@@ -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
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 :
|
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.
|
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 :
|
25
|
-
|
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] = { :
|
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(:
|
42
|
+
let(:parsed_data) { subject.request(_method: :get, _path: "/foo")[:parsed_data] }
|
40
43
|
before do
|
41
|
-
subject.setup :
|
44
|
+
subject.setup url: "https://api.example.com" do |builder|
|
42
45
|
builder.use SimpleParser
|
43
|
-
builder.adapter(:test) { |stub| stub.get("/foo") {
|
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].
|
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(:
|
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 :
|
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][
|
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].
|
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(:
|
67
|
+
let(:parsed_data) { subject.request(_method: :get, _path: "users/1")[:parsed_data] }
|
65
68
|
before do
|
66
|
-
subject.setup :
|
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") {
|
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].
|
76
|
-
parsed_data[:errors].
|
77
|
-
parsed_data[:metadata].
|
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(:
|
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], :
|
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
|
-
:
|
91
|
-
:
|
92
|
-
:
|
93
|
+
data: json,
|
94
|
+
errors: errors,
|
95
|
+
metadata: metadata
|
93
96
|
}
|
94
97
|
end
|
95
98
|
end
|
96
99
|
|
97
|
-
subject.setup :
|
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") {
|
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].
|
108
|
-
parsed_data[:errors].
|
109
|
-
parsed_data[:metadata].
|
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
|
data/spec/collection_spec.rb
CHANGED
@@ -1,26 +1,41 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe Her::Collection do
|
4
|
-
|
5
4
|
let(:items) { [1, 2, 3, 4] }
|
6
|
-
let(:metadata) { { :
|
7
|
-
let(:errors) { { :
|
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 {
|
14
|
-
|
15
|
-
|
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 {
|
22
|
-
|
23
|
-
|
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
|