rescue_groups 0.0.1

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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +3 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +90 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +226 -0
  8. data/Rakefile +30 -0
  9. data/config/config.rb +26 -0
  10. data/config/initializer.rb +15 -0
  11. data/docs/animal_field.md +138 -0
  12. data/docs/event_field.md +20 -0
  13. data/docs/organization_field.md +25 -0
  14. data/fields/animal_field.rb +152 -0
  15. data/fields/event_field.rb +35 -0
  16. data/fields/organization_field.rb +40 -0
  17. data/fields/picture_field.rb +30 -0
  18. data/lib/api_client.rb +29 -0
  19. data/lib/queryable.rb +79 -0
  20. data/lib/relationable.rb +76 -0
  21. data/lib/remote_client.rb +29 -0
  22. data/lib/remote_model.rb +47 -0
  23. data/lib/requests/find.rb +29 -0
  24. data/lib/requests/invalid_client.rb +1 -0
  25. data/lib/requests/where.rb +94 -0
  26. data/lib/response.rb +48 -0
  27. data/models/animal.rb +57 -0
  28. data/models/event.rb +41 -0
  29. data/models/organization.rb +41 -0
  30. data/models/picture.rb +26 -0
  31. data/rescue_groups.gemspec +28 -0
  32. data/rescue_groups.rb +27 -0
  33. data/search/animal_search.rb +15 -0
  34. data/search/base_search.rb +72 -0
  35. data/search/event_search.rb +15 -0
  36. data/search/filter.rb +49 -0
  37. data/search/organization_search.rb +15 -0
  38. data/spec/fixtures/animal/find.json +1 -0
  39. data/spec/fixtures/animal/where.json +1 -0
  40. data/spec/fixtures/error.json +20 -0
  41. data/spec/fixtures/event/find.json +1 -0
  42. data/spec/fixtures/event/where.json +1 -0
  43. data/spec/fixtures/organization/find.json +1 -0
  44. data/spec/fixtures/organization/where.json +1 -0
  45. data/spec/fixtures/test_constants.rb +12 -0
  46. data/spec/integration/animal_spec.rb +55 -0
  47. data/spec/integration/event_spec.rb +33 -0
  48. data/spec/integration/organization_spec.rb +35 -0
  49. data/spec/lib/queryable_spec.rb +257 -0
  50. data/spec/lib/relationable_spec.rb +113 -0
  51. data/spec/lib/remote_client_spec.rb +27 -0
  52. data/spec/lib/requests/find_spec.rb +97 -0
  53. data/spec/lib/requests/where_spec.rb +267 -0
  54. data/spec/lib/response_spec.rb +99 -0
  55. data/spec/models/animal_spec.rb +131 -0
  56. data/spec/models/event_spec.rb +105 -0
  57. data/spec/models/organization_spec.rb +112 -0
  58. data/spec/models/picture_spec.rb +87 -0
  59. data/spec/search/animal_search_spec.rb +8 -0
  60. data/spec/search/event_search_spec.rb +8 -0
  61. data/spec/search/filter_spec.rb +39 -0
  62. data/spec/search/organization_search_spec.rb +8 -0
  63. data/spec/spec_helper.rb +340 -0
  64. data/spec/support/model_spec.rb +47 -0
  65. data/spec/support/searchable_spec.rb +15 -0
  66. data/support/animal_mock.rb +215 -0
  67. data/support/base_mock.rb +44 -0
  68. data/support/event_mock.rb +48 -0
  69. data/support/organization_mock.rb +53 -0
  70. data/version.rb +3 -0
  71. metadata +242 -0
@@ -0,0 +1,113 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/relationable'
3
+
4
+ module RescueGroups
5
+ class OtherClass;end
6
+
7
+ class YetAnotherClass
8
+ def self.where(anything); [] end
9
+ end
10
+
11
+ class IncludedClass
12
+ include Relationable
13
+ belongs_to :other_class
14
+ has_many :yet_another_classes
15
+
16
+ def initialize(other_class:, yet_another_classes:)
17
+ self.other_class = other_class
18
+ self.yet_another_classes = yet_another_classes
19
+ end
20
+ end
21
+
22
+ describe 'Relationable' do
23
+ subject { IncludedClass.new(other_class: other_class, yet_another_classes: yet_another_classes) }
24
+ let(:other_class) { nil }
25
+ let(:yet_another_classes) { nil }
26
+
27
+ describe '#belongs_to' do
28
+ it 'makes a setter method' do
29
+ expect(subject).to respond_to(:other_class=)
30
+ end
31
+
32
+ it 'makes a getter method' do
33
+ expect(subject).to respond_to(:other_class)
34
+ end
35
+
36
+ it 'makes a setter relationship_id method' do
37
+ expect(subject).to respond_to(:other_class_id=)
38
+ end
39
+
40
+ it 'makes a getter relationship_id method' do
41
+ expect(subject).to respond_to(:other_class_id)
42
+ end
43
+
44
+ context 'relationship model exists' do
45
+ let(:other_class) { OtherClass.new }
46
+ it 'returns a model of the specified class' do
47
+ expect(subject.other_class).to be_a(OtherClass)
48
+ end
49
+ end
50
+
51
+ context 'relationship model is nil' do
52
+ it 'returns nil' do
53
+ expect(subject.other_class).to be_nil
54
+ end
55
+ end
56
+
57
+ context 'relationship_id is set model is not present' do
58
+ let(:other_class_id) { 1 }
59
+ it 'fetches the model' do
60
+ subject.other_class_id = other_class_id
61
+ expect(OtherClass).to receive(:find).with(other_class_id)
62
+ subject.other_class
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#has_many' do
68
+ it 'makes a setter method' do
69
+ expect(subject).to respond_to(:yet_another_classes=)
70
+ end
71
+
72
+ it 'makes a getter method' do
73
+ expect(subject).to respond_to(:yet_another_classes)
74
+ end
75
+
76
+ context 'relationship models exist' do
77
+ let(:yet_another_class) { YetAnotherClass.new }
78
+ let(:yet_another_classes) { [yet_another_class] }
79
+
80
+ context 'one model exists' do
81
+ it 'returns an array of size 1' do
82
+ expect(subject.yet_another_classes.length).to eq(1)
83
+ end
84
+
85
+ it 'the model in the relationship is of the specified class' do
86
+ subject.yet_another_classes.each do |yac|
87
+ expect(yac).to be_a(YetAnotherClass)
88
+ end
89
+ end
90
+ end
91
+
92
+ context 'more than one model exists' do
93
+ let(:yet_another_classes) { [YetAnotherClass.new, YetAnotherClass.new] }
94
+ it 'returns an array the size of the relationship' do
95
+ expect(subject.yet_another_classes.length).to eq(2)
96
+ end
97
+
98
+ it 'all models in the relationship are of the specified class' do
99
+ subject.yet_another_classes.each do |yac|
100
+ expect(yac).to be_a(YetAnotherClass)
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ context 'relationship model does not exist' do
107
+ it 'returns an empty array' do
108
+ expect(subject.yet_another_classes).to eq([])
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,27 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/remote_client'
3
+
4
+ module RescueGroups
5
+ describe RemoteClient do
6
+ describe '#post_and_respond' do
7
+ before do
8
+ allow(Response).to receive(:new)
9
+ end
10
+
11
+ it 'calls the class post method' do
12
+ expect(described_class).to receive(:post)
13
+ subject.post_and_respond({})
14
+ end
15
+
16
+ context 'with no api key' do
17
+ before do
18
+ allow(RescueGroups.config).to receive(:apikey) { nil }
19
+ end
20
+
21
+ it 'raises an error' do
22
+ expect { subject.post_and_respond({}) }.to raise_error('No RescueGroups API Key set')
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,97 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/requests/find'
3
+
4
+ module RescueGroups
5
+ module Requests
6
+ describe Find do
7
+ class TestFields
8
+ FIELDS = {}
9
+ def self.all; end
10
+ end
11
+
12
+ test_model = Struct.new("TestModel")
13
+ test_client = Struct.new("TestClient")
14
+
15
+ describe '#initalize' do
16
+ subject { described_class.new(ids, anything, anything) }
17
+
18
+ let(:ids) { [1] }
19
+
20
+ it 'sets @ids to the passed in value' do
21
+ expect(subject.instance_variable_get(:@ids)).to eq(ids)
22
+ end
23
+
24
+ context 'a single id is given' do
25
+ let(:ids) { 42 }
26
+
27
+ it 'sets them correctly' do
28
+ expect(subject.instance_variable_get(:@ids)).to eq([ids])
29
+ end
30
+ end
31
+
32
+ context 'multiple ids are given' do
33
+ let(:ids) { [120, 203, 399] }
34
+
35
+ it 'sets them correctly' do
36
+ expect(subject.instance_variable_get(:@ids)).to eq(ids)
37
+ end
38
+
39
+ context 'with duplicates' do
40
+ let(:ids) { [101, 101, 120, 399, 120, 203, 399] }
41
+
42
+ it 'removes the duplicates' do
43
+ expect(subject.instance_variable_get(:@ids)).to eq(ids.uniq)
44
+ end
45
+ end
46
+ end
47
+
48
+ context 'something other than an integer or an array is given' do
49
+ let(:ids) { Object.new }
50
+
51
+ it 'raises error' do
52
+ expect { subject }.to raise_error(/Only initialize a Requests::Find/)
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#request' do
58
+ before do
59
+ allow(test_model).to receive(:object_type)
60
+ allow(test_model).to receive(:object_fields) { TestFields }
61
+ end
62
+
63
+ subject { described_class.new(1, test_model, test_client) }
64
+
65
+ it 'composes the request given the passed in objects' do
66
+ expect(subject.instance_variable_get(:@client)).to receive(:post_and_respond)
67
+ expect(subject).to receive(:as_json)
68
+ subject.request
69
+ end
70
+
71
+ context 'client is improper object' do
72
+ it 'raises error' do
73
+ expect { subject.request }.to raise_error(InvalidClient, /Invalid client/)
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#as_json' do
79
+ before do
80
+ allow(test_model).to receive(:object_type)
81
+ allow(test_model).to receive(:object_fields) { TestFields }
82
+ end
83
+
84
+ subject { described_class.new(1, test_model, anything) }
85
+
86
+ it 'has the correct keys' do
87
+ json_result = subject.as_json
88
+
89
+ expect(json_result).to have_key(:objectAction)
90
+ expect(json_result).to have_key(:objectType)
91
+ expect(json_result).to have_key(:fields)
92
+ expect(json_result).to have_key(:values)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,267 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/requests/where'
3
+
4
+ module RescueGroups
5
+ module Requests
6
+ describe Where do
7
+ class TestFields
8
+ FIELDS = { some_test_field: 'SomeTestField' }
9
+ def self.all; end
10
+ end
11
+
12
+ class TestSearchEngine < Struct.new(:limit, :start, :sort, :order)
13
+ def add_filter(*args)
14
+ end
15
+ end
16
+
17
+ test_model = Struct.new('TestModel')
18
+ test_client = Struct.new('TestClient')
19
+
20
+ let(:conditions) { search_conditions }
21
+ let(:search_conditions) { {} }
22
+
23
+ subject { described_class.new(conditions, test_model, test_client, TestSearchEngine) }
24
+
25
+ describe '#initialize' do
26
+ it 'sets the conditions' do
27
+ expect(subject.instance_variable_get(:@conditions)).to eq(search_conditions)
28
+ end
29
+
30
+ context 'with search modifiers present' do
31
+ let(:limit) { 10 }
32
+ let(:start) { 30 }
33
+ let(:sort) { :breed }
34
+ let(:order) { :asc }
35
+ let(:conditions) { search_conditions.merge(limit: limit, start: start, sort: sort, order: order) }
36
+
37
+ it 'does not include the modifiers in the search conditions' do
38
+ expect(subject.instance_variable_get(:@conditions)).to eq(search_conditions)
39
+ end
40
+
41
+ context 'limit' do
42
+ it 'sets an instance variable for the modifier' do
43
+ expect(subject.instance_variable_get(:@limit)).to eq(limit)
44
+ end
45
+ end
46
+
47
+ context 'start' do
48
+ it 'sets an instance variable for the modifier' do
49
+ expect(subject.instance_variable_get(:@start)).to eq(start)
50
+ end
51
+ end
52
+
53
+ context 'sort' do
54
+ it 'sets an instance variable for the modifier' do
55
+ expect(subject.instance_variable_get(:@sort)).to eq(sort)
56
+ end
57
+ end
58
+
59
+ context 'order' do
60
+ it 'sets an instance variable for the modifier' do
61
+ expect(subject.instance_variable_get(:@order)).to eq(order)
62
+ end
63
+ end
64
+ end
65
+
66
+ it 'calls search_engine' do
67
+ expect_any_instance_of(described_class).to receive(:build_search_engine)
68
+ subject
69
+ end
70
+ end
71
+
72
+ describe '#request' do
73
+ let(:response) do
74
+ TestResponse.new(200,
75
+ { 'status' => 'ok', 'data' => {}, 'found_rows' => 0 })
76
+ end
77
+
78
+ before do
79
+ allow(test_model).to receive(:object_type)
80
+ allow(test_model).to receive(:object_fields) { TestFields }
81
+ allow_any_instance_of(TestSearchEngine).to receive(:as_json)
82
+ end
83
+
84
+ it 'composes the request given the passed in objects' do
85
+ expect(subject.instance_variable_get(:@client)).to receive(:post_and_respond) { response }
86
+ expect(subject).to receive(:as_json)
87
+ subject.request
88
+ end
89
+
90
+ context 'client is improper object' do
91
+ it 'raises error' do
92
+ expect { subject.request }.to raise_error(InvalidClient, /Invalid client.*Where/)
93
+ end
94
+ end
95
+ end
96
+
97
+ describe '#as_json' do
98
+ before do
99
+ allow(test_model).to receive(:object_type)
100
+ allow(test_model).to receive(:object_fields) { TestFields }
101
+ allow_any_instance_of(TestSearchEngine).to receive(:as_json)
102
+ end
103
+
104
+ it 'has the correct keys' do
105
+ json_result = subject.as_json
106
+
107
+ expect(json_result).to have_key(:objectAction)
108
+ expect(json_result).to have_key(:objectType)
109
+ expect(json_result).to have_key(:search)
110
+ end
111
+ end
112
+
113
+ describe '#can_request_more?' do
114
+ let(:response) { { 'data' => data, 'found_rows' => found_rows } }
115
+ let(:data) { {} }
116
+ let(:found_rows) { 0 }
117
+
118
+ before do
119
+ subject.instance_variable_set(:@results, response)
120
+ end
121
+
122
+ context 'response returns no results' do
123
+ it 'returns false' do
124
+ expect(subject.can_request_more?).to eq(false)
125
+ end
126
+ end
127
+
128
+ context 'response does not return a found_rows count' do
129
+ let(:found_rows) { nil }
130
+
131
+ it 'returns false' do
132
+ expect(subject.can_request_more?).to eq(false)
133
+ end
134
+ end
135
+
136
+ context 'response returns found_rows and results' do
137
+ let(:data) { { foo: anything, bar: anything } }
138
+
139
+ context 'returned rows is less than found_rows' do
140
+ let(:found_rows) { 3 }
141
+
142
+ it 'returns true' do
143
+ expect(subject.can_request_more?).to eq(true)
144
+ end
145
+ end
146
+
147
+ context 'returned rows is equal to found_rows' do
148
+ let(:found_rows) { 2 }
149
+
150
+ it 'returns false' do
151
+ expect(subject.can_request_more?).to eq(false)
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ describe '!#conditions_to_rescue_groups_key_value' do
158
+ before do
159
+ allow(test_model).to receive(:object_fields) { TestFields }
160
+ allow_any_instance_of(TestSearchEngine).to receive(:add_filter)
161
+ end
162
+
163
+ context 'all filters have mappings' do
164
+ let(:conditions) { { some_test_field: value } }
165
+ let(:value) { 'foo' }
166
+
167
+ it 'yields to the block for all filters' do
168
+ expect do |b|
169
+ subject.send(:conditions_to_rescue_groups_key_value, &b)
170
+ end.to yield_with_args('SomeTestField', value)
171
+ end
172
+ end
173
+
174
+ context 'some filters have mappings, others do not' do
175
+ let(:conditions) { { some_test_field: value, another_test_field: anything } }
176
+ let(:value) { 'foo' }
177
+
178
+ it 'yields to the block only for mapped filters' do
179
+ expect do |b|
180
+ subject.send(:conditions_to_rescue_groups_key_value, &b)
181
+ end.to yield_with_args('SomeTestField', value)
182
+ end
183
+ end
184
+
185
+ context 'no filters have mappings' do
186
+ let(:conditions) { { foo: :bar } }
187
+ it 'does not yield to the block' do
188
+ expect do |b|
189
+ subject.send(:conditions_to_rescue_groups_key_value, &b)
190
+ end.to_not yield_control
191
+ end
192
+ end
193
+
194
+ context 'no block is given' do
195
+ it 'raises an error' do
196
+ expect do
197
+ subject.send(:conditions_to_rescue_groups_key_value)
198
+ end.to raise_error(/Block not given/)
199
+ end
200
+ end
201
+ end
202
+
203
+ describe '!#build_search_engine' do
204
+ let(:instance_vars_to_set) { {} }
205
+
206
+ before do
207
+ instance_vars_to_set.each do |key, value|
208
+ subject.instance_variable_set(:"@#{ key }", value)
209
+ end
210
+ end
211
+
212
+ context 'modifiers exist in conditions' do
213
+ context 'multiple modifiers' do
214
+ let(:instance_vars_to_set) { { limit: 100, start: 100 } }
215
+
216
+ it 'initializes searh engine with all modifiers' do
217
+ expect(TestSearchEngine).to receive(:new).with(limit: 100, start: 100)
218
+ subject.send(:build_search_engine, TestSearchEngine)
219
+ end
220
+ end
221
+
222
+ context 'a single modifier' do
223
+ let(:instance_vars_to_set) { { limit: 10 } }
224
+
225
+ it 'initializes searh engine with the modifier' do
226
+ expect(TestSearchEngine).to receive(:new).with(limit: 10)
227
+ subject.send(:build_search_engine, TestSearchEngine)
228
+ end
229
+ end
230
+ end
231
+
232
+ context 'modifiers do not exist in the conditions' do
233
+ it 'initializes searh engine without any args' do
234
+ subject
235
+ expect(TestSearchEngine).to receive(:new).with({})
236
+ subject.send(:build_search_engine, TestSearchEngine)
237
+ end
238
+ end
239
+ end
240
+
241
+ describe '!#add_filters_to_search_engine' do
242
+ context 'conditions are not empty' do
243
+ let(:conditions) { { foo: :bar } }
244
+
245
+ before do
246
+ allow_any_instance_of(described_class)
247
+ .to receive(:conditions_to_rescue_groups_key_value).with(no_args).and_yield(:foo, :bar)
248
+ end
249
+
250
+ it 'calls add_filter per condition' do
251
+ subject
252
+ expect_any_instance_of(TestSearchEngine)
253
+ .to receive(:add_filter).with(:foo, :equal, :bar)
254
+ subject.send(:add_filters_to_search_engine, TestSearchEngine.new)
255
+ end
256
+ end
257
+
258
+ context 'conditions are empty' do
259
+ it 'does not call add_filter' do
260
+ expect_any_instance_of(TestSearchEngine).to_not receive(:add_filter)
261
+ subject.send(:add_filters_to_search_engine, TestSearchEngine.new)
262
+ end
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end