test_track_rails_client 0.9.7 → 0.9.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +11 -8
- data/lib/test_track_rails_client/version.rb +1 -1
- data/vendor/gems/fakeable_her/fakeable_her.gemspec +22 -0
- data/vendor/gems/fakeable_her/lib/fakeable_her/model.rb +148 -0
- data/vendor/gems/fakeable_her/lib/fakeable_her/version.rb +3 -0
- data/vendor/gems/fakeable_her/lib/fakeable_her.rb +5 -0
- data/vendor/gems/her/CONTRIBUTING.md +26 -0
- data/vendor/gems/her/Gemfile +10 -0
- data/vendor/gems/her/LICENSE +7 -0
- data/vendor/gems/her/README.md +1023 -0
- data/vendor/gems/her/Rakefile +11 -0
- data/vendor/gems/her/UPGRADE.md +101 -0
- data/vendor/gems/her/gemfiles/Gemfile.activemodel-3.2.x +7 -0
- data/vendor/gems/her/gemfiles/Gemfile.activemodel-4.0 +7 -0
- data/vendor/gems/her/gemfiles/Gemfile.activemodel-4.1 +7 -0
- data/vendor/gems/her/gemfiles/Gemfile.activemodel-4.2 +7 -0
- data/vendor/gems/her/her.gemspec +31 -0
- data/vendor/gems/her/lib/her/api.rb +119 -0
- data/vendor/gems/her/lib/her/collection.rb +12 -0
- data/vendor/gems/her/lib/her/error_collection.rb +15 -0
- data/vendor/gems/her/lib/her/errors.rb +40 -0
- data/vendor/gems/her/lib/her/json_api/model.rb +46 -0
- data/vendor/gems/her/lib/her/middleware/accept_json.rb +17 -0
- data/vendor/gems/her/lib/her/middleware/first_level_parse_json.rb +36 -0
- data/vendor/gems/her/lib/her/middleware/json_api_parser.rb +36 -0
- data/vendor/gems/her/lib/her/middleware/parse_json.rb +21 -0
- data/vendor/gems/her/lib/her/middleware/second_level_parse_json.rb +36 -0
- data/vendor/gems/her/lib/her/middleware.rb +12 -0
- data/vendor/gems/her/lib/her/model/active_model_overrides.rb +13 -0
- data/vendor/gems/her/lib/her/model/associations/association.rb +106 -0
- data/vendor/gems/her/lib/her/model/associations/association_proxy.rb +46 -0
- data/vendor/gems/her/lib/her/model/associations/belongs_to_association.rb +96 -0
- data/vendor/gems/her/lib/her/model/associations/has_many_association.rb +100 -0
- data/vendor/gems/her/lib/her/model/associations/has_one_association.rb +79 -0
- data/vendor/gems/her/lib/her/model/associations.rb +141 -0
- data/vendor/gems/her/lib/her/model/attributes.rb +304 -0
- data/vendor/gems/her/lib/her/model/base.rb +33 -0
- data/vendor/gems/her/lib/her/model/deprecated_methods.rb +61 -0
- data/vendor/gems/her/lib/her/model/http.rb +117 -0
- data/vendor/gems/her/lib/her/model/introspection.rb +65 -0
- data/vendor/gems/her/lib/her/model/nested_attributes.rb +45 -0
- data/vendor/gems/her/lib/her/model/orm.rb +219 -0
- data/vendor/gems/her/lib/her/model/parse.rb +215 -0
- data/vendor/gems/her/lib/her/model/paths.rb +126 -0
- data/vendor/gems/her/lib/her/model/relation.rb +251 -0
- data/vendor/gems/her/lib/her/model.rb +81 -0
- data/vendor/gems/her/lib/her/version.rb +3 -0
- data/vendor/gems/her/lib/her.rb +20 -0
- data/vendor/gems/her/spec/api_spec.rb +114 -0
- data/vendor/gems/her/spec/collection_spec.rb +26 -0
- data/vendor/gems/her/spec/error_collection_spec.rb +33 -0
- data/vendor/gems/her/spec/json_api/model_spec.rb +168 -0
- data/vendor/gems/her/spec/middleware/accept_json_spec.rb +10 -0
- data/vendor/gems/her/spec/middleware/first_level_parse_json_spec.rb +62 -0
- data/vendor/gems/her/spec/middleware/json_api_parser_spec.rb +32 -0
- data/vendor/gems/her/spec/middleware/second_level_parse_json_spec.rb +35 -0
- data/vendor/gems/her/spec/model/associations/association_proxy_spec.rb +31 -0
- data/vendor/gems/her/spec/model/associations_spec.rb +504 -0
- data/vendor/gems/her/spec/model/attributes_spec.rb +404 -0
- data/vendor/gems/her/spec/model/callbacks_spec.rb +145 -0
- data/vendor/gems/her/spec/model/dirty_spec.rb +110 -0
- data/vendor/gems/her/spec/model/http_spec.rb +165 -0
- data/vendor/gems/her/spec/model/introspection_spec.rb +76 -0
- data/vendor/gems/her/spec/model/nested_attributes_spec.rb +134 -0
- data/vendor/gems/her/spec/model/orm_spec.rb +791 -0
- data/vendor/gems/her/spec/model/parse_spec.rb +372 -0
- data/vendor/gems/her/spec/model/paths_spec.rb +347 -0
- data/vendor/gems/her/spec/model/relation_spec.rb +226 -0
- data/vendor/gems/her/spec/model/validations_spec.rb +42 -0
- data/vendor/gems/her/spec/model_spec.rb +31 -0
- data/vendor/gems/her/spec/spec_helper.rb +27 -0
- data/vendor/gems/her/spec/support/extensions/array.rb +5 -0
- data/vendor/gems/her/spec/support/extensions/hash.rb +5 -0
- data/vendor/gems/her/spec/support/macros/her_macros.rb +17 -0
- data/vendor/gems/her/spec/support/macros/model_macros.rb +36 -0
- data/vendor/gems/her/spec/support/macros/request_macros.rb +27 -0
- data/vendor/gems/publicsuffix-ruby/CHANGELOG.md +236 -0
- data/vendor/gems/publicsuffix-ruby/Gemfile +3 -0
- data/vendor/gems/publicsuffix-ruby/LICENSE.txt +22 -0
- data/vendor/gems/publicsuffix-ruby/README.md +151 -0
- data/vendor/gems/publicsuffix-ruby/Rakefile +109 -0
- data/vendor/gems/publicsuffix-ruby/lib/definitions.txt +11467 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/domain.rb +387 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/errors.rb +53 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/list.rb +302 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/rule.rb +373 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/version.rb +23 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix.rb +131 -0
- data/vendor/gems/publicsuffix-ruby/public_suffix.gemspec +39 -0
- data/vendor/gems/publicsuffix-ruby/test/acceptance_test.rb +42 -0
- data/vendor/gems/publicsuffix-ruby/test/test_helper.rb +6 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/domain_test.rb +170 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/errors_test.rb +23 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/list_test.rb +179 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/public_suffix_test.rb +115 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/rule_test.rb +307 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/capybara_configuration.rb +98 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/matchers.rb +151 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rspec_configuration.rb +34 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rubocop/cop/betterment/html_safe.rb +15 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rubocop/cop/betterment/raw.rb +15 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rubocop/cop/betterment/safe_concat.rb +15 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rubocop.rb +3 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/shared_examples/betterment_application_examples.rb +47 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/shared_examples.rb +1 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/site_prism_configuration.rb +42 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/site_prism_dropdown.rb +17 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/version.rb +3 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/webmock_configuration.rb +8 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers.rb +2 -0
- data/vendor/gems/ruby_spec_helpers/ruby_spec_helpers.gemspec +25 -0
- metadata +110 -1
@@ -0,0 +1,251 @@
|
|
1
|
+
module Her
|
2
|
+
module Model
|
3
|
+
class Relation
|
4
|
+
# @private
|
5
|
+
attr_accessor :params, :request_headers, :request_options
|
6
|
+
|
7
|
+
# @private
|
8
|
+
def initialize(parent)
|
9
|
+
@parent = parent
|
10
|
+
@params = {}
|
11
|
+
@request_headers = {}
|
12
|
+
@request_options = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# @private
|
16
|
+
def apply_to(attributes)
|
17
|
+
@params.merge(attributes)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Build a new resource
|
21
|
+
def build(attributes = {})
|
22
|
+
@parent.build(@params.merge(attributes))
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_request_headers(headers = {})
|
26
|
+
return self if headers.blank?
|
27
|
+
self.clone.tap do |r|
|
28
|
+
r.request_headers = r.request_headers.merge!(headers)
|
29
|
+
r.clear_fetch_cache!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def with_request_options(options = {})
|
34
|
+
return self if options.blank?
|
35
|
+
self.clone.tap do |r|
|
36
|
+
r.request_options = r.request_options.merge!(options)
|
37
|
+
r.clear_fetch_cache!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add a query string parameter
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# @users = User.all
|
45
|
+
# # Fetched via GET "/users"
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# @users = User.where(:approved => 1).all
|
49
|
+
# # Fetched via GET "/users?approved=1"
|
50
|
+
def where(params = {})
|
51
|
+
return self if params.blank? && !@_fetch.nil?
|
52
|
+
self.clone.tap do |r|
|
53
|
+
r.params = r.params.merge(params)
|
54
|
+
r.clear_fetch_cache!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
alias all where
|
58
|
+
|
59
|
+
# Bubble all methods to the fetched collection
|
60
|
+
#
|
61
|
+
# @private
|
62
|
+
def method_missing(method, *args, &blk)
|
63
|
+
fetch.send(method, *args, &blk)
|
64
|
+
end
|
65
|
+
|
66
|
+
# @private
|
67
|
+
def respond_to?(method, *args)
|
68
|
+
super || fetch.respond_to?(method, *args)
|
69
|
+
end
|
70
|
+
|
71
|
+
# @private
|
72
|
+
def nil?
|
73
|
+
fetch.nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
# @private
|
77
|
+
def kind_of?(thing)
|
78
|
+
fetch.kind_of?(thing)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Fetch a collection of resources
|
82
|
+
#
|
83
|
+
# @private
|
84
|
+
def fetch
|
85
|
+
@_fetch ||= begin
|
86
|
+
path = @parent.build_request_path(@params)
|
87
|
+
method = @parent.method_for(:find)
|
88
|
+
@parent.request(@params.merge(:_method => method, :_path => path, :_headers => request_headers, :_options => request_options)) do |parsed_data, response|
|
89
|
+
@parent.new_collection(parsed_data)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Fetch specific resource by some of its attributes
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# @user = User.find_by(id: 1)
|
98
|
+
# # Fetched via GET "/users/1"
|
99
|
+
#
|
100
|
+
# @example
|
101
|
+
# @users = User.find_by(id: 1, age: 25)
|
102
|
+
# # Fetched via GET "/users/1?age=25"
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# @users = User.find_by(age: 25)
|
106
|
+
# # Fetched via GET "/users?age=25"
|
107
|
+
# # locally limit to single result
|
108
|
+
def find_by(params = {})
|
109
|
+
where(params).first
|
110
|
+
end
|
111
|
+
|
112
|
+
# Fetch first result
|
113
|
+
#
|
114
|
+
# @example
|
115
|
+
# @user = User.where(id: 1).first
|
116
|
+
# # Fetched via GET "/users/1"
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
# @users = User.where(id: 1, age: 25)
|
120
|
+
# # Fetched via GET "/users/1?age=25"
|
121
|
+
#
|
122
|
+
# @example
|
123
|
+
# @users = User.where(age: 25)
|
124
|
+
# # Fetched via GET "/users?age=25"
|
125
|
+
# # locally limit to single result
|
126
|
+
#
|
127
|
+
# @example
|
128
|
+
# @users = User.where(id: [1, 2])
|
129
|
+
# # Fetched via GET "/users?id[]=1&id[]=2"
|
130
|
+
# # locally limit to single result
|
131
|
+
def first
|
132
|
+
id_param = self.params[@parent.primary_key]
|
133
|
+
|
134
|
+
if id_param && !id_param.is_a?(Array)
|
135
|
+
self.params.delete(@parent.primary_key)
|
136
|
+
request_params = self.params.merge(
|
137
|
+
:_method => @parent.method_for(:find),
|
138
|
+
:_path => @parent.build_request_path(self.params.merge(@parent.primary_key => id_param)),
|
139
|
+
:_headers => request_headers,
|
140
|
+
:_options => request_options
|
141
|
+
)
|
142
|
+
@parent.request(request_params) do |parsed_data, response|
|
143
|
+
if response.success?
|
144
|
+
resource = @parent.new_from_parsed_data(parsed_data)
|
145
|
+
resource.instance_variable_set(:@changed_attributes, {})
|
146
|
+
resource.run_callbacks :find
|
147
|
+
resource
|
148
|
+
elsif [404, 410].include? response.status
|
149
|
+
nil
|
150
|
+
else
|
151
|
+
raise Her::Errors::ResponseError.for(response.status).new("Request against #{@parent.name} returned a #{response.status}")
|
152
|
+
end
|
153
|
+
end
|
154
|
+
else
|
155
|
+
fetch.first
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Fetch specific resource(s) by their ID
|
160
|
+
#
|
161
|
+
# @example
|
162
|
+
# @user = User.find(1)
|
163
|
+
# # Fetched via GET "/users/1"
|
164
|
+
#
|
165
|
+
# @example
|
166
|
+
# @users = User.find([1, 2])
|
167
|
+
# # Fetched via GET "/users/1" and GET "/users/2"
|
168
|
+
def find(*ids)
|
169
|
+
params = @params.merge(ids.last.is_a?(Hash) ? ids.pop : {})
|
170
|
+
ids = Array(params[@parent.primary_key]) if params.key?(@parent.primary_key)
|
171
|
+
|
172
|
+
results = ids.flatten.compact.uniq.map do |id|
|
173
|
+
resource = nil
|
174
|
+
request_params = params.merge(
|
175
|
+
:_method => @parent.method_for(:find),
|
176
|
+
:_path => @parent.build_request_path(params.merge(@parent.primary_key => id)),
|
177
|
+
:_headers => request_headers,
|
178
|
+
:_options => request_options
|
179
|
+
)
|
180
|
+
|
181
|
+
@parent.request(request_params) do |parsed_data, response|
|
182
|
+
if response.success?
|
183
|
+
resource = @parent.new_from_parsed_data(parsed_data)
|
184
|
+
resource.instance_variable_set(:@changed_attributes, {})
|
185
|
+
resource.run_callbacks :find
|
186
|
+
else
|
187
|
+
raise Her::Errors::ResponseError.for(response.status).new("Request against #{@parent.name} returned a #{response.status}")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
resource
|
192
|
+
end
|
193
|
+
|
194
|
+
ids.length > 1 || ids.first.kind_of?(Array) ? results : results.first
|
195
|
+
end
|
196
|
+
|
197
|
+
# Create a resource and return it
|
198
|
+
#
|
199
|
+
# @example
|
200
|
+
# @user = User.create(:fullname => "Tobias Fünke")
|
201
|
+
# # Called via POST "/users/1" with `&fullname=Tobias+Fünke`
|
202
|
+
#
|
203
|
+
# @example
|
204
|
+
# @user = User.where(:email => "tobias@bluth.com").create(:fullname => "Tobias Fünke")
|
205
|
+
# # Called via POST "/users/1" with `&email=tobias@bluth.com&fullname=Tobias+Fünke`
|
206
|
+
def create(attributes = {})
|
207
|
+
attributes ||= {}
|
208
|
+
resource = @parent.new(@params.merge(attributes))
|
209
|
+
resource.request_headers = request_headers
|
210
|
+
resource.request_options = request_options
|
211
|
+
resource.save
|
212
|
+
|
213
|
+
resource
|
214
|
+
end
|
215
|
+
|
216
|
+
# Fetch a resource and create it if it's not found
|
217
|
+
#
|
218
|
+
# @example
|
219
|
+
# @user = User.where(:email => "remi@example.com").find_or_create
|
220
|
+
#
|
221
|
+
# # Returns the first item of the collection if present:
|
222
|
+
# # GET "/users?email=remi@example.com"
|
223
|
+
#
|
224
|
+
# # If collection is empty:
|
225
|
+
# # POST /users with `email=remi@example.com`
|
226
|
+
def first_or_create(attributes = {})
|
227
|
+
fetch.first || create(attributes)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Fetch a resource and build it if it's not found
|
231
|
+
#
|
232
|
+
# @example
|
233
|
+
# @user = User.where(:email => "remi@example.com").find_or_initialize
|
234
|
+
#
|
235
|
+
# # Returns the first item of the collection if present:
|
236
|
+
# # GET "/users?email=remi@example.com"
|
237
|
+
#
|
238
|
+
# # If collection is empty:
|
239
|
+
# @user.email # => "remi@example.com"
|
240
|
+
# @user.new? # => true
|
241
|
+
def first_or_initialize(attributes = {})
|
242
|
+
fetch.first || build(attributes)
|
243
|
+
end
|
244
|
+
|
245
|
+
# @private
|
246
|
+
def clear_fetch_cache!
|
247
|
+
instance_variable_set(:@_fetch, nil)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "her/model/base"
|
2
|
+
require "her/model/deprecated_methods"
|
3
|
+
require "her/model/http"
|
4
|
+
require "her/model/attributes"
|
5
|
+
require "her/model/relation"
|
6
|
+
require "her/model/orm"
|
7
|
+
require "her/model/parse"
|
8
|
+
require "her/model/associations"
|
9
|
+
require "her/model/introspection"
|
10
|
+
require "her/model/paths"
|
11
|
+
require "her/model/nested_attributes"
|
12
|
+
require "her/model/active_model_overrides"
|
13
|
+
require "active_model"
|
14
|
+
|
15
|
+
module Her
|
16
|
+
# This module is the main element of Her. After creating a Her::API object,
|
17
|
+
# include this module in your models to get a few magic methods defined in them.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# class User
|
21
|
+
# include Her::Model
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# @user = User.new(:name => "Rémi")
|
25
|
+
# @user.save
|
26
|
+
module Model
|
27
|
+
extend ActiveSupport::Concern
|
28
|
+
|
29
|
+
# Her modules
|
30
|
+
include Her::Model::Base
|
31
|
+
include Her::Model::DeprecatedMethods
|
32
|
+
include Her::Model::Attributes
|
33
|
+
include Her::Model::ORM
|
34
|
+
include Her::Model::HTTP
|
35
|
+
include Her::Model::Parse
|
36
|
+
include Her::Model::Introspection
|
37
|
+
include Her::Model::Paths
|
38
|
+
include Her::Model::Associations
|
39
|
+
include Her::Model::NestedAttributes
|
40
|
+
|
41
|
+
# Supported ActiveModel modules
|
42
|
+
include ActiveModel::AttributeMethods
|
43
|
+
include ActiveModel::Validations
|
44
|
+
include ActiveModel::Validations::Callbacks
|
45
|
+
include ActiveModel::Conversion
|
46
|
+
include ActiveModel::Dirty
|
47
|
+
|
48
|
+
include Her::Model::ActiveModelOverrides
|
49
|
+
|
50
|
+
# Class methods
|
51
|
+
included do
|
52
|
+
# Assign the default API
|
53
|
+
use_api Her::API.default_api
|
54
|
+
method_for :create, :post
|
55
|
+
method_for :update, :put
|
56
|
+
method_for :find, :get
|
57
|
+
method_for :destroy, :delete
|
58
|
+
method_for :new, :get
|
59
|
+
|
60
|
+
# Define the default primary key
|
61
|
+
primary_key :id
|
62
|
+
|
63
|
+
# Define default storage accessors for errors and metadata
|
64
|
+
store_response_errors :response_errors
|
65
|
+
store_metadata :metadata
|
66
|
+
|
67
|
+
# provide a place to store headers and options to be added to requests
|
68
|
+
attr_accessor :request_headers, :request_options
|
69
|
+
|
70
|
+
# Include ActiveModel naming methods
|
71
|
+
extend ActiveModel::Translation
|
72
|
+
|
73
|
+
# Configure ActiveModel callbacks
|
74
|
+
extend ActiveModel::Callbacks
|
75
|
+
define_model_callbacks :create, :update, :save, :find, :destroy, :initialize
|
76
|
+
|
77
|
+
# Define matchers for attr? and attr= methods
|
78
|
+
define_attribute_method_matchers
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "her/version"
|
2
|
+
|
3
|
+
require "multi_json"
|
4
|
+
require "faraday"
|
5
|
+
require "active_support"
|
6
|
+
require "active_support/inflector"
|
7
|
+
require "active_support/core_ext/hash"
|
8
|
+
|
9
|
+
require "her/model"
|
10
|
+
require "her/api"
|
11
|
+
require "her/middleware"
|
12
|
+
require "her/errors"
|
13
|
+
require "her/collection"
|
14
|
+
require "her/error_collection"
|
15
|
+
|
16
|
+
module Her
|
17
|
+
module JsonApi
|
18
|
+
autoload :Model, 'her/json_api/model'
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.join(File.dirname(__FILE__), "spec_helper.rb")
|
3
|
+
|
4
|
+
describe Her::API do
|
5
|
+
subject { Her::API.new }
|
6
|
+
|
7
|
+
context "initialization" do
|
8
|
+
describe "#setup" do
|
9
|
+
context "when setting custom middleware" do
|
10
|
+
before do
|
11
|
+
class Foo; end;
|
12
|
+
class Bar; end;
|
13
|
+
|
14
|
+
subject.setup :url => "https://api.example.com" do |connection|
|
15
|
+
connection.use Foo
|
16
|
+
connection.use Bar
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
specify { subject.connection.builder.handlers.should == [Foo, Bar] }
|
21
|
+
end
|
22
|
+
|
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" } }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#request" do
|
30
|
+
before do
|
31
|
+
class SimpleParser < Faraday::Response::Middleware
|
32
|
+
def on_complete(env)
|
33
|
+
env[:body] = { :data => env[:body] }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "making HTTP requests" do
|
39
|
+
let(:parsed_data) { subject.request(:_method => :get, :_path => "/foo")[:parsed_data] }
|
40
|
+
before do
|
41
|
+
subject.setup :url => "https://api.example.com" do |builder|
|
42
|
+
builder.use SimpleParser
|
43
|
+
builder.adapter(:test) { |stub| stub.get("/foo") { |env| [200, {}, "Foo, it is."] } }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
specify { parsed_data[:data].should == "Foo, it is." }
|
48
|
+
end
|
49
|
+
|
50
|
+
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] }
|
52
|
+
|
53
|
+
before do
|
54
|
+
subject.setup :url => "https://api.example.com" do |builder|
|
55
|
+
builder.use SimpleParser
|
56
|
+
builder.adapter(:test) { |stub| stub.get("/foo") { |env| [200, {}, "Foo, it is page #{env[:request_headers]["X-Page"]}."] } }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
specify { parsed_data[:data].should == "Foo, it is page 2." }
|
61
|
+
end
|
62
|
+
|
63
|
+
context "parsing a request with the default parser" do
|
64
|
+
let(:parsed_data) { subject.request(:_method => :get, :_path => "users/1")[:parsed_data] }
|
65
|
+
before do
|
66
|
+
subject.setup :url => "https://api.example.com" do |builder|
|
67
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
68
|
+
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 } })] }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
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
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "parsing a request with a custom parser" do
|
82
|
+
let(:parsed_data) { subject.request(:_method => :get, :_path => "users/1")[:parsed_data] }
|
83
|
+
before do
|
84
|
+
class CustomParser < Faraday::Response::Middleware
|
85
|
+
def on_complete(env)
|
86
|
+
json = MultiJson.load(env[:body], :symbolize_keys => true)
|
87
|
+
errors = json.delete(:errors) || []
|
88
|
+
metadata = json.delete(:metadata) || {}
|
89
|
+
env[:body] = {
|
90
|
+
:data => json,
|
91
|
+
:errors => errors,
|
92
|
+
:metadata => metadata,
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
subject.setup :url => "https://api.example.com" do |builder|
|
98
|
+
builder.use CustomParser
|
99
|
+
builder.use Faraday::Request::UrlEncoded
|
100
|
+
builder.adapter :test do |stub|
|
101
|
+
stub.get("/users/1") { |env| [200, {}, MultiJson.dump(:id => 1, :name => "George Michael Bluth")] }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
specify do
|
107
|
+
parsed_data[:data].should == { :id => 1, :name => "George Michael Bluth" }
|
108
|
+
parsed_data[:errors].should == []
|
109
|
+
parsed_data[:metadata].should == {}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Her::Collection do
|
4
|
+
|
5
|
+
let(:items) { [1, 2, 3, 4] }
|
6
|
+
let(:metadata) { { :name => 'Testname' } }
|
7
|
+
let(:errors) { { :name => ['not_present'] } }
|
8
|
+
|
9
|
+
describe "#new" do
|
10
|
+
context "without parameters" do
|
11
|
+
subject { Her::Collection.new }
|
12
|
+
|
13
|
+
it { should eq([]) }
|
14
|
+
its(:metadata) { should eq({}) }
|
15
|
+
its(:errors) { should eq({}) }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "with parameters" do
|
19
|
+
subject { Her::Collection.new(items, metadata, errors) }
|
20
|
+
|
21
|
+
it { should eq([1,2,3,4]) }
|
22
|
+
its(:metadata) { should eq({ :name => 'Testname' }) }
|
23
|
+
its(:errors) { should eq({ :name => ['not_present'] }) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Her::ErrorCollection do
|
4
|
+
|
5
|
+
let(:metadata) { { :name => 'Testname' } }
|
6
|
+
let(:errors) { { :name => ['not_present'] } }
|
7
|
+
|
8
|
+
describe "#new" do
|
9
|
+
context "without parameters" do
|
10
|
+
subject { Her::ErrorCollection.new }
|
11
|
+
|
12
|
+
it "raises upon access" do
|
13
|
+
expect { subject[0] }.to raise_error(Her::Errors::ResponseError, "Cannot access collection, Request returned an error")
|
14
|
+
expect { subject.last }.to raise_error(Her::Errors::ResponseError, "Cannot access collection, Request returned an error")
|
15
|
+
end
|
16
|
+
|
17
|
+
its(:metadata) { should eq({}) }
|
18
|
+
its(:errors) { should eq({}) }
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with parameters" do
|
22
|
+
subject { Her::ErrorCollection.new(metadata, errors) }
|
23
|
+
|
24
|
+
it "raises upon access" do
|
25
|
+
expect { subject[0] }.to raise_error(Her::Errors::ResponseError, "Cannot access collection, Request returned an error")
|
26
|
+
expect { subject.last }.to raise_error(Her::Errors::ResponseError, "Cannot access collection, Request returned an error")
|
27
|
+
end
|
28
|
+
|
29
|
+
its(:metadata) { should eq({ :name => 'Testname' }) }
|
30
|
+
its(:errors) { should eq({ :name => ['not_present'] }) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Her::JsonApi::Model do
|
4
|
+
before do
|
5
|
+
Her::API.setup :url => "https://api.example.com" do |connection|
|
6
|
+
connection.use Her::Middleware::JsonApiParser
|
7
|
+
connection.adapter :test do |stub|
|
8
|
+
stub.get("/users/1") do |env|
|
9
|
+
[
|
10
|
+
200,
|
11
|
+
{},
|
12
|
+
{
|
13
|
+
data: {
|
14
|
+
id: 1,
|
15
|
+
type: 'users',
|
16
|
+
attributes: {
|
17
|
+
name: "Roger Federer",
|
18
|
+
},
|
19
|
+
}
|
20
|
+
|
21
|
+
}.to_json
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
stub.get("/users") do |env|
|
26
|
+
[
|
27
|
+
200,
|
28
|
+
{},
|
29
|
+
{
|
30
|
+
data: [
|
31
|
+
{
|
32
|
+
id: 1,
|
33
|
+
type: 'users',
|
34
|
+
attributes: {
|
35
|
+
name: "Roger Federer",
|
36
|
+
},
|
37
|
+
},
|
38
|
+
{
|
39
|
+
id: 2,
|
40
|
+
type: 'users',
|
41
|
+
attributes: {
|
42
|
+
name: "Kei Nishikori",
|
43
|
+
},
|
44
|
+
}
|
45
|
+
]
|
46
|
+
}.to_json
|
47
|
+
]
|
48
|
+
end
|
49
|
+
|
50
|
+
stub.post("/users", data: {
|
51
|
+
type: 'users',
|
52
|
+
attributes: {
|
53
|
+
name: "Jeremy Lin",
|
54
|
+
},
|
55
|
+
}) do |env|
|
56
|
+
[
|
57
|
+
201,
|
58
|
+
{},
|
59
|
+
{
|
60
|
+
data: {
|
61
|
+
id: 3,
|
62
|
+
type: 'users',
|
63
|
+
attributes: {
|
64
|
+
name: 'Jeremy Lin',
|
65
|
+
},
|
66
|
+
}
|
67
|
+
|
68
|
+
}.to_json
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
stub.patch("/users/1", data: {
|
73
|
+
type: 'users',
|
74
|
+
id: 1,
|
75
|
+
attributes: {
|
76
|
+
name: "Fed GOAT",
|
77
|
+
},
|
78
|
+
}) do |env|
|
79
|
+
[
|
80
|
+
200,
|
81
|
+
{},
|
82
|
+
{
|
83
|
+
data: {
|
84
|
+
id: 1,
|
85
|
+
type: 'users',
|
86
|
+
attributes: {
|
87
|
+
name: 'Fed GOAT',
|
88
|
+
},
|
89
|
+
}
|
90
|
+
|
91
|
+
}.to_json
|
92
|
+
]
|
93
|
+
end
|
94
|
+
|
95
|
+
stub.delete("/users/1") { |env|
|
96
|
+
[ 204, {}, {}, ]
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
spawn_model("Foo::User", type: Her::JsonApi::Model)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'allows configuration of type' do
|
106
|
+
spawn_model("Foo::Bar", type: Her::JsonApi::Model) do
|
107
|
+
type :foobars
|
108
|
+
end
|
109
|
+
|
110
|
+
expect(Foo::Bar.instance_variable_get('@type')).to eql('foobars')
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'finds models by id' do
|
114
|
+
user = Foo::User.find(1)
|
115
|
+
expect(user.attributes).to eql(
|
116
|
+
'id' => 1,
|
117
|
+
'name' => 'Roger Federer',
|
118
|
+
)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'finds a collection of models' do
|
122
|
+
users = Foo::User.all
|
123
|
+
expect(users.map(&:attributes)).to match_array([
|
124
|
+
{
|
125
|
+
'id' => 1,
|
126
|
+
'name' => 'Roger Federer',
|
127
|
+
},
|
128
|
+
{
|
129
|
+
'id' => 2,
|
130
|
+
'name' => 'Kei Nishikori',
|
131
|
+
}
|
132
|
+
])
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'creates a Foo::User' do
|
136
|
+
user = Foo::User.new(name: 'Jeremy Lin')
|
137
|
+
user.save
|
138
|
+
expect(user.attributes).to eql(
|
139
|
+
'id' => 3,
|
140
|
+
'name' => 'Jeremy Lin',
|
141
|
+
'status_code' => 201
|
142
|
+
)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'updates a Foo::User' do
|
146
|
+
user = Foo::User.find(1)
|
147
|
+
user.name = 'Fed GOAT'
|
148
|
+
user.save
|
149
|
+
expect(user.attributes).to eql(
|
150
|
+
'id' => 1,
|
151
|
+
'name' => 'Fed GOAT',
|
152
|
+
'status_code' => 200
|
153
|
+
)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'destroys a Foo::User' do
|
157
|
+
user = Foo::User.find(1)
|
158
|
+
expect(user.destroy).to be_destroyed
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'undefined methods' do
|
162
|
+
it 'removes methods that are not compatible with json api' do
|
163
|
+
[:parse_root_in_json, :include_root_in_json, :root_element, :primary_key].each do |method|
|
164
|
+
expect { Foo::User.new.send(method, :foo) }.to raise_error NoMethodError, "Her::JsonApi::Model does not support the #{method} configuration option"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|