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,20 @@
1
+ ## Event Fields
2
+ * id
3
+ * org_id
4
+ * name
5
+ * event_start
6
+ * event_end
7
+ * url
8
+ * description
9
+ * location_id
10
+ * species
11
+ * location_name
12
+ * location_url
13
+ * location_address
14
+ * location_city
15
+ * location_state
16
+ * location_postal_code
17
+ * location_country
18
+ * location_phone
19
+ * location_phone_ext
20
+ * location_events
@@ -0,0 +1,25 @@
1
+ ## Organization Fields
2
+ * id
3
+ * about
4
+ * adoption_process
5
+ * adoption_url
6
+ * common_application_accept
7
+ * donation_url
8
+ * email
9
+ * facebook_url
10
+ * fax
11
+ * location
12
+ * location_address
13
+ * location_city
14
+ * location_country
15
+ * location_postal
16
+ * location_state
17
+ * location_zip_plus_4
18
+ * meet_pets
19
+ * name
20
+ * phone
21
+ * serve_areas
22
+ * services
23
+ * sponsorship_url
24
+ * type
25
+ * website_url
@@ -0,0 +1,152 @@
1
+ module RescueGroups
2
+ class AnimalField
3
+ FIELDS = {
4
+ id: :animalID,
5
+ organization_id: :animalOrgID,
6
+ activity_level: :animalActivityLevel,
7
+ adoption_fee: :animalAdoptionFee,
8
+ altered: :animalAltered,
9
+ available_date: :animalAvailableDate,
10
+ birthdate: :animalBirthdate,
11
+ birthdate_exact: :animalBirthdateExact,
12
+ breed: :animalBreed,
13
+ coat_length: :animalCoatLength,
14
+ color: :animalColor,
15
+ color_id: :animalColorID,
16
+ color_details: :animalColorDetails,
17
+ courtesy: :animalCourtesy,
18
+ declawed: :animalDeclawed,
19
+ description: :animalDescription,
20
+ description_plain: :animalDescriptionPlain,
21
+ distinguishing_marks: :animalDistinguishingMarks,
22
+ ear_type: :animalEarType,
23
+ energy_level: :animalEnergyLevel,
24
+ excercise_needs: :animalExerciseNeeds,
25
+ eye_color: :animalEyeColor,
26
+ fence: :animalFence,
27
+ found: :animalFound,
28
+ found_date: :animalFoundDate,
29
+ found_postal_code: :animalFoundPostalcode,
30
+ general_age: :animalGeneralAge,
31
+ general_size_potential: :animalGeneralSizePotential,
32
+ grooming_needs: :animalGroomingNeeds,
33
+ house_trained: :animalHousetrained,
34
+ indoor_outdoor: :animalIndoorOutdoor,
35
+ kill_date: :animalKillDate,
36
+ kill_reason: :animalKillReason,
37
+ location: :animalLocation,
38
+ # location_distance: :animalLocationDistance,
39
+ location_city_state: :animalLocationCitystate,
40
+ microchipped: :animalMicrochipped,
41
+ mixed_breed: :animalMixedBreed,
42
+ name: :animalName,
43
+ special_needs: :animalSpecialneeds,
44
+ special_needs_description: :animalSpecialneedsDescription,
45
+ needs_foster: :animalNeedsFoster,
46
+ new_people: :animalNewPeople,
47
+ not_house_trained_reason: :animalNotHousetrainedReason,
48
+ obedience_training: :animalObedienceTraining,
49
+ ok_with_adults: :animalOKWithAdults,
50
+ ok_with_cats: :animalOKWithCats,
51
+ ok_with_dogs: :animalOKWithDogs,
52
+ ok_with_kids: :animalOKWithKids,
53
+ owner_experience: :animalOwnerExperience,
54
+ pattern: :animalPattern,
55
+ pattern_id: :animalPatternID,
56
+ adoption_pending: :animalAdoptionPending,
57
+ primary_breed: :animalPrimaryBreed,
58
+ primary_breed_id: :animalPrimaryBreedID,
59
+ rescue_id: :animalRescueID,
60
+ search_string: :animalSearchString,
61
+ secondary_breed: :animalSecondaryBreed,
62
+ secondary_breed_id: :animalSecondaryBreedID,
63
+ sex: :animalSex,
64
+ shedding: :animalShedding,
65
+ size_current: :animalSizeCurrent,
66
+ size_potential: :animalSizePotential,
67
+ size_uom: :animalSizeUOM,
68
+ species: :animalSpecies,
69
+ species_id: :animalSpeciesID,
70
+ sponsorable: :animalSponsorable,
71
+ sponsors: :animalSponsors,
72
+ sponsorhip_details: :animalSponsorshipDetails,
73
+ sponsorship_minimum: :animalSponsorshipMinimum,
74
+ status: :animalStatus,
75
+ status_id: :animalStatusID,
76
+ summary: :animalSummary,
77
+ tail_type: :animalTailType,
78
+ thumbnail_url: :animalThumbnailUrl,
79
+ up_to_date: :animalUptodate,
80
+ updated_date: :animalUpdatedDate,
81
+ url: :animalUrl,
82
+ vocal: :animalVocal,
83
+ yard_required: :animalYardRequired,
84
+ affectionate: :animalAffectionate,
85
+ apartment: :animalApartment,
86
+ crate_trained: :animalCratetrained,
87
+ drools: :animalDrools,
88
+ eager_to_please: :animalEagerToPlease,
89
+ escapes: :animalEscapes,
90
+ even_tempered: :animalEventempered,
91
+ fetches: :animalFetches,
92
+ gentle: :animalGentle,
93
+ good_in_car: :animalGoodInCar,
94
+ goofy: :animalGoofy,
95
+ has_allergies: :animalHasAllergies,
96
+ hearing_impaired: :animalHearingImpaired,
97
+ hypoallergenic: :animalHypoallergenic,
98
+ independent: :animalIndependent,
99
+ intelligent: :animalIntelligent,
100
+ lap: :animalLap,
101
+ leash_trained: :animalLeashtrained,
102
+ needs_companion_animal: :animalNeedsCompanionAnimal,
103
+ no_cold: :animalNoCold,
104
+ no_female_dogs: :animalNoFemaleDogs,
105
+ no_heat: :animalNoHeat,
106
+ no_large_dogs: :animalNoLargeDogs,
107
+ no_male_dogs: :animalNoMaleDogs,
108
+ no_small_dogs: :animalNoSmallDogs,
109
+ obedient: :animalObedient,
110
+ ok_for_seniors: :animalOKForSeniors,
111
+ ok_with_farm_animals: :animalOKWithFarmAnimals,
112
+ older_kids_only: :animalOlderKidsOnly,
113
+ ongoing_medical: :animalOngoingMedical,
114
+ playful: :animalPlayful,
115
+ plays_toys: :animalPlaysToys,
116
+ predatory: :animalPredatory,
117
+ protective: :animalProtective,
118
+ sight_impaired: :animalSightImpaired,
119
+ skittish: :animalSkittish,
120
+ special_diet: :animalSpecialDiet,
121
+ swims: :animalSwims,
122
+ timid: :animalTimid,
123
+ foster_email: :fosterEmail,
124
+ foster_first_name: :fosterFirstname,
125
+ foster_last_name: :fosterLastname,
126
+ foster_name: :fosterName,
127
+ foster_phone_cell: :fosterPhoneCell,
128
+ foster_phone_home: :fosterPhoneHome,
129
+ foster_salutation: :fosterSalutation,
130
+ location_addresss: :locationAddress,
131
+ location_city: :locationCity,
132
+ location_country: :locationCountry,
133
+ location_url: :locationUrl,
134
+ location_name: :locationName,
135
+ location_phone: :locationPhone,
136
+ location_state: :locationState,
137
+ location_postal_code: :locationPostalcode,
138
+ pictures: :animalPictures,
139
+ videos: :animalVideos,
140
+ video_urls: :animalVideoUrls,
141
+ }.freeze
142
+
143
+ # method: all
144
+ # purpose: Return the values of FIELDS for easy use in
145
+ # requesting fields from the remote API
146
+ # param: none
147
+ # return: <Array[Symbol]> - All defined field names
148
+ def self.all
149
+ FIELDS.values
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,35 @@
1
+ module RescueGroups
2
+ class EventField
3
+ FIELDS = {
4
+ id: :eventID,
5
+ org_id: :eventOrgID,
6
+ name: :eventName,
7
+ event_start: :eventStart,
8
+ event_end: :eventEnd,
9
+ url: :eventUrl,
10
+ description: :eventDescription,
11
+ location_id: :eventLocationID,
12
+ # location_distance: :eventLocationDistance, # seems to have been deprecated
13
+ species: :eventSpecies,
14
+ location_name: :locationName,
15
+ location_url: :locationUrl,
16
+ location_address: :locationAddress,
17
+ location_city: :locationCity,
18
+ location_state: :locationState,
19
+ location_postal_code: :locationPostalcode,
20
+ location_country: :locationCountry,
21
+ location_phone: :locationPhone,
22
+ location_phone_ext: :locationPhoneExt,
23
+ location_events: :locationEvents,
24
+ }.freeze
25
+
26
+ # method: all
27
+ # purpose: Return the values of FIELDS for easy use in
28
+ # requesting fields from the remote API
29
+ # param: none
30
+ # return: <Array[Symbol]> - All defined field names
31
+ def self.all
32
+ FIELDS.values
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ module RescueGroups
2
+ class OrganizationField
3
+ FIELDS = {
4
+ about: :orgAbout,
5
+ adoption_process: :orgAdoptionProcess,
6
+ adoption_url: :orgAdoptionUrl,
7
+ common_application_accept: :orgCommonapplicationAccept,
8
+ donation_url: :orgDonationUrl,
9
+ email: :orgEmail,
10
+ facebook_url: :orgFacebookUrl,
11
+ fax: :orgFax,
12
+ id: :orgID,
13
+ location: :orgLocation,
14
+ location_address: :orgAddress,
15
+ location_city: :orgCity,
16
+ location_country: :orgCountry,
17
+ # location_distance: :orgLocationDistance, # Seems to have been removed
18
+ location_postal: :orgPostalcode,
19
+ location_state: :orgState,
20
+ location_zip_plus_4: :orgPlus4,
21
+ meet_pets: :orgMeetPets,
22
+ name: :orgName,
23
+ phone: :orgPhone,
24
+ serve_areas: :orgServeAreas,
25
+ services: :orgServices,
26
+ sponsorship_url: :orgSponsorshipUrl,
27
+ type: :orgType,
28
+ website_url: :orgWebsiteUrl,
29
+ }.freeze
30
+
31
+ # method: all
32
+ # purpose: Return the values of FIELDS for easy use in
33
+ # requesting fields from the remote API
34
+ # param: none
35
+ # return: <Array[Symbol]> - All defined field names
36
+ def self.all
37
+ FIELDS.values
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ module RescueGroups
2
+ class PictureField
3
+ FIELDS = {
4
+ mediaID: :id,
5
+ mediaOrder: :order,
6
+ lastUpdated: :updated_at,
7
+ fileSize: :file_size,
8
+ resolutionX: :resolution_x,
9
+ resolutionY: :resolution_y,
10
+ fileNameFullsize: :file_name_full_size,
11
+ fileNameThumbnail: :file_name_thumbnail,
12
+ urlSecureFullsize: :url_full,
13
+ urlSecureThumbnail: :url_thumbnail,
14
+ urlInsecureFullsize: :insecure_url_full,
15
+ urlInsecureThumbnail: :insecure_url_thumb,
16
+ original: :original,
17
+ large: :large,
18
+ small: :small
19
+ }.freeze
20
+
21
+ # method: all
22
+ # purpose: Return the values of FIELDS for easy use in
23
+ # requesting fields from the remote API
24
+ # param: none
25
+ # return: <Array[Symbol]> - All defined field names
26
+ def self.all
27
+ FIELDS.values
28
+ end
29
+ end
30
+ end
data/lib/api_client.rb ADDED
@@ -0,0 +1,29 @@
1
+ require_relative './remote_client'
2
+
3
+ module RescueGroups
4
+ module ApiClient
5
+ # This method is called when the ApiClient Module is included
6
+ # in a class.
7
+ def self.included(base)
8
+ base.class_eval do
9
+ # method: api_client
10
+ # purpose: Return or instantiate a new RemoteClient class to
11
+ # handle all details of talking to the third party
12
+ # RescueGroups API
13
+ # param: none
14
+ # return: RemoteClient
15
+ def self.api_client
16
+ @api_client ||= RemoteClient.new
17
+ end
18
+
19
+ # method: api_client
20
+ # purpose: delegate to class method to retrieve remote client
21
+ # param: none
22
+ # return: result of self.api_client
23
+ def api_client
24
+ self.class.api_client
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/queryable.rb ADDED
@@ -0,0 +1,79 @@
1
+ require_relative './requests/find'
2
+ require_relative './requests/where'
3
+
4
+ module RescueGroups
5
+ class NotFound < StandardError; end
6
+ class InvalidRequest < StandardError; end
7
+
8
+ module Queryable
9
+ # This method is called when the Queryable Module is included
10
+ # in a class.
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+
15
+ module ClassMethods
16
+ # method: find
17
+ # purpose: find one or many objects by primary key (id)
18
+ # param: ids Array<Integer> primary key(s) of object(s) that will
19
+ # be requested
20
+ # return: One found object if one id was given, otherwise an array of found objects
21
+ # If the response was not successful, an exception is thrown
22
+ def find(ids)
23
+ find_request = Requests::Find.new(ids, self, api_client)
24
+
25
+ response = find_request.request
26
+
27
+ unless response.success? && !response['data'].nil? && !response['data'].empty?
28
+ fail(NotFound, "Unable to find #{ self.name } with id: #{ ids }")
29
+ end
30
+
31
+ objects = response['data'].map { |data| new(data) }
32
+
33
+ [*ids].flatten.length == 1 ? objects.first : objects
34
+ end
35
+
36
+ # method: where
37
+ # purpose: find one or many objects by any supported filters
38
+ # param: conditions - <Hash> - mutliple keyed hash containing
39
+ # the conditions to search against.
40
+ # example: { breed: 'daschund' }
41
+ # return: <Array> -An array of found objects
42
+ # If the response was not successful, an exception is thrown
43
+ def where(conditions)
44
+ return find(conditions[:id]) if conditions.keys == [:id]
45
+
46
+ where_request = Requests::Where.new(conditions, self, api_client, search_engine_class)
47
+
48
+ response = where_request.request
49
+
50
+ fail(InvalidRequest, "Problem with request #{ response.error }") unless response.success?
51
+
52
+ response_with_additional = additional_request_data(where_request)
53
+
54
+ response_with_additional['data'].map do |_data_id, data|
55
+ new(data)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def additional_request_data(request)
62
+ unless RescueGroups.config.load_all_results && request.can_request_more?
63
+ return request.results
64
+ end
65
+
66
+ (request.results['found_rows'] / request.search_engine.limit).times.each do |i|
67
+ request.update_conditions!(limit: request.search_engine.limit * (i + 1))
68
+
69
+ additional_results_response = request.request
70
+ if !additional_results_response.success?
71
+ fail(InvalidRequest, "Problem with request #{ additional_results_response.error }")
72
+ end
73
+ end
74
+
75
+ request.results
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,76 @@
1
+ module RescueGroups
2
+ module Relationable
3
+ # This method is called when the Relationable Module is included
4
+ # in a class.
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ # method: belongs_to
11
+ # purpose: define methods that denote a relationship
12
+ # between the class including this module
13
+ # and another.
14
+ # When included, it defines methods: relationship_id
15
+ # relationship_id=
16
+ # relationship
17
+ # relationship=
18
+ # example:
19
+ # class Foo
20
+ # include Relationable
21
+ #
22
+ # belongs_to :bar
23
+ # end
24
+ #
25
+ # param: relationship - <Symbol> - name of the class that a relationship
26
+ # is intended for
27
+ # return: nil
28
+ def belongs_to(relationship)
29
+ define_method relationship do
30
+ model = instance_variable_get(:"@#{ relationship }")
31
+ return model unless model.nil?
32
+
33
+ relationship_id = self.send(:"#{ relationship }_id")
34
+
35
+ unless relationship_id.nil?
36
+ klass = RescueGroups.constantize(relationship)
37
+
38
+ self.send(:"#{ relationship }=", klass.find(relationship_id))
39
+ end
40
+ end
41
+
42
+ attr_writer relationship
43
+ attr_accessor :"#{ relationship }_id"
44
+ end
45
+ # method: has_many
46
+ # purpose: define methods that denote a relationship
47
+ # between the class including this module
48
+ # and another.
49
+ # When included, it defines methods: relationship
50
+ # relationship=
51
+ # example:
52
+ # class Foo
53
+ # include Relationable
54
+ #
55
+ # has_many :bars
56
+ # end
57
+ #
58
+ # param: relationship - <Symbol> - name of the class that a relationship
59
+ # is intended for
60
+ # return: nil
61
+ def has_many(relationship)
62
+ define_method relationship do
63
+ temp = instance_variable_get(:"@#{ relationship }")
64
+
65
+ return temp unless temp.nil? || temp.empty?
66
+
67
+ klass = RescueGroups.constantize(relationship)
68
+ foreign_key = "#{ self.class.to_s.split('::').last.downcase }_id"
69
+ klass.where(foreign_key.to_sym => @id)
70
+ end
71
+
72
+ attr_writer relationship
73
+ end
74
+ end
75
+ end
76
+ end