spark_api 1.0.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 (257) hide show
  1. data/History.txt +139 -0
  2. data/LICENSE +14 -0
  3. data/README.md +153 -0
  4. data/Rakefile +18 -0
  5. data/VERSION +1 -0
  6. data/bin/spark_api +8 -0
  7. data/bin/spark_api~ +8 -0
  8. data/lib/spark_api.rb +46 -0
  9. data/lib/spark_api/authentication.rb +55 -0
  10. data/lib/spark_api/authentication/api_auth.rb +104 -0
  11. data/lib/spark_api/authentication/api_auth.rb~ +104 -0
  12. data/lib/spark_api/authentication/base_auth.rb +47 -0
  13. data/lib/spark_api/authentication/base_auth.rb~ +47 -0
  14. data/lib/spark_api/authentication/oauth2.rb +198 -0
  15. data/lib/spark_api/authentication/oauth2.rb~ +199 -0
  16. data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb +87 -0
  17. data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb~ +87 -0
  18. data/lib/spark_api/authentication/oauth2_impl/grant_type_code.rb +48 -0
  19. data/lib/spark_api/authentication/oauth2_impl/grant_type_code.rb~ +49 -0
  20. data/lib/spark_api/authentication/oauth2_impl/grant_type_password.rb +44 -0
  21. data/lib/spark_api/authentication/oauth2_impl/grant_type_password.rb~ +45 -0
  22. data/lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb +35 -0
  23. data/lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb~ +36 -0
  24. data/lib/spark_api/authentication/oauth2_impl/middleware.rb +38 -0
  25. data/lib/spark_api/authentication/oauth2_impl/middleware.rb~ +39 -0
  26. data/lib/spark_api/authentication/oauth2_impl/password_provider.rb +24 -0
  27. data/lib/spark_api/authentication/oauth2_impl/password_provider.rb~ +25 -0
  28. data/lib/spark_api/cli.rb +158 -0
  29. data/lib/spark_api/cli.rb~ +158 -0
  30. data/lib/spark_api/cli/api_auth.rb +8 -0
  31. data/lib/spark_api/cli/api_auth.rb~ +8 -0
  32. data/lib/spark_api/cli/oauth2.rb +14 -0
  33. data/lib/spark_api/cli/oauth2.rb~ +14 -0
  34. data/lib/spark_api/cli/setup.rb +47 -0
  35. data/lib/spark_api/cli/setup.rb~ +47 -0
  36. data/lib/spark_api/client.rb +27 -0
  37. data/lib/spark_api/configuration.rb +54 -0
  38. data/lib/spark_api/configuration.rb~ +54 -0
  39. data/lib/spark_api/configuration/yaml.rb +101 -0
  40. data/lib/spark_api/configuration/yaml.rb~ +101 -0
  41. data/lib/spark_api/connection.rb +42 -0
  42. data/lib/spark_api/faraday.rb +64 -0
  43. data/lib/spark_api/faraday.rb~ +64 -0
  44. data/lib/spark_api/models.rb +33 -0
  45. data/lib/spark_api/models.rb~ +33 -0
  46. data/lib/spark_api/models/account.rb +115 -0
  47. data/lib/spark_api/models/account.rb~ +115 -0
  48. data/lib/spark_api/models/base.rb +118 -0
  49. data/lib/spark_api/models/base.rb~ +118 -0
  50. data/lib/spark_api/models/connect_prefs.rb +10 -0
  51. data/lib/spark_api/models/connect_prefs.rb~ +10 -0
  52. data/lib/spark_api/models/constraint.rb +16 -0
  53. data/lib/spark_api/models/constraint.rb~ +16 -0
  54. data/lib/spark_api/models/contact.rb +49 -0
  55. data/lib/spark_api/models/contact.rb~ +49 -0
  56. data/lib/spark_api/models/custom_fields.rb +12 -0
  57. data/lib/spark_api/models/custom_fields.rb~ +12 -0
  58. data/lib/spark_api/models/document.rb +11 -0
  59. data/lib/spark_api/models/document.rb~ +11 -0
  60. data/lib/spark_api/models/finders.rb +45 -0
  61. data/lib/spark_api/models/finders.rb~ +45 -0
  62. data/lib/spark_api/models/idx_link.rb +47 -0
  63. data/lib/spark_api/models/idx_link.rb~ +47 -0
  64. data/lib/spark_api/models/listing.rb +197 -0
  65. data/lib/spark_api/models/listing.rb~ +197 -0
  66. data/lib/spark_api/models/listing_cart.rb +72 -0
  67. data/lib/spark_api/models/listing_cart.rb~ +72 -0
  68. data/lib/spark_api/models/market_statistics.rb +33 -0
  69. data/lib/spark_api/models/market_statistics.rb~ +33 -0
  70. data/lib/spark_api/models/message.rb +21 -0
  71. data/lib/spark_api/models/message.rb~ +21 -0
  72. data/lib/spark_api/models/note.rb +41 -0
  73. data/lib/spark_api/models/note.rb~ +41 -0
  74. data/lib/spark_api/models/notification.rb +42 -0
  75. data/lib/spark_api/models/notification.rb~ +42 -0
  76. data/lib/spark_api/models/open_house.rb +24 -0
  77. data/lib/spark_api/models/open_house.rb~ +24 -0
  78. data/lib/spark_api/models/photo.rb +70 -0
  79. data/lib/spark_api/models/photo.rb~ +70 -0
  80. data/lib/spark_api/models/property_types.rb +7 -0
  81. data/lib/spark_api/models/property_types.rb~ +7 -0
  82. data/lib/spark_api/models/saved_search.rb +16 -0
  83. data/lib/spark_api/models/saved_search.rb~ +16 -0
  84. data/lib/spark_api/models/shared_listing.rb +35 -0
  85. data/lib/spark_api/models/shared_listing.rb~ +35 -0
  86. data/lib/spark_api/models/standard_fields.rb +50 -0
  87. data/lib/spark_api/models/standard_fields.rb~ +50 -0
  88. data/lib/spark_api/models/subresource.rb +19 -0
  89. data/lib/spark_api/models/subresource.rb~ +19 -0
  90. data/lib/spark_api/models/system_info.rb +14 -0
  91. data/lib/spark_api/models/system_info.rb~ +14 -0
  92. data/lib/spark_api/models/tour_of_home.rb +24 -0
  93. data/lib/spark_api/models/tour_of_home.rb~ +24 -0
  94. data/lib/spark_api/models/video.rb +16 -0
  95. data/lib/spark_api/models/video.rb~ +16 -0
  96. data/lib/spark_api/models/virtual_tour.rb +18 -0
  97. data/lib/spark_api/models/virtual_tour.rb~ +18 -0
  98. data/lib/spark_api/multi_client.rb +59 -0
  99. data/lib/spark_api/multi_client.rb~ +59 -0
  100. data/lib/spark_api/paginate.rb +109 -0
  101. data/lib/spark_api/paginate.rb~ +109 -0
  102. data/lib/spark_api/primary_array.rb +29 -0
  103. data/lib/spark_api/primary_array.rb~ +29 -0
  104. data/lib/spark_api/request.rb +96 -0
  105. data/lib/spark_api/request.rb~ +96 -0
  106. data/lib/spark_api/response.rb +70 -0
  107. data/lib/spark_api/response.rb~ +70 -0
  108. data/lib/spark_api/version.rb +4 -0
  109. data/lib/spark_api/version.rb~ +4 -0
  110. data/script/console +6 -0
  111. data/script/console~ +6 -0
  112. data/script/example.rb +27 -0
  113. data/script/example.rb~ +27 -0
  114. data/spec/fixtures/accounts/all.json +160 -0
  115. data/spec/fixtures/accounts/my.json +74 -0
  116. data/spec/fixtures/accounts/my_portal.json +20 -0
  117. data/spec/fixtures/accounts/my_put.json +5 -0
  118. data/spec/fixtures/accounts/my_save.json +5 -0
  119. data/spec/fixtures/accounts/office.json +142 -0
  120. data/spec/fixtures/accounts/password_save.json +6 -0
  121. data/spec/fixtures/authentication_failure.json +7 -0
  122. data/spec/fixtures/base.json +13 -0
  123. data/spec/fixtures/contacts/contacts.json +28 -0
  124. data/spec/fixtures/contacts/my.json +19 -0
  125. data/spec/fixtures/contacts/new.json +11 -0
  126. data/spec/fixtures/contacts/new_empty.json +8 -0
  127. data/spec/fixtures/contacts/new_notify.json +11 -0
  128. data/spec/fixtures/contacts/post.json +10 -0
  129. data/spec/fixtures/contacts/tags.json +11 -0
  130. data/spec/fixtures/count.json +10 -0
  131. data/spec/fixtures/empty.json +3 -0
  132. data/spec/fixtures/errors/expired.json +7 -0
  133. data/spec/fixtures/errors/failure.json +5 -0
  134. data/spec/fixtures/errors/failure_with_constraint.json +17 -0
  135. data/spec/fixtures/errors/failure_with_msg.json +7 -0
  136. data/spec/fixtures/generic_delete.json +1 -0
  137. data/spec/fixtures/generic_failure.json +5 -0
  138. data/spec/fixtures/listing_carts/add_listing.json +13 -0
  139. data/spec/fixtures/listing_carts/add_listing_post.json +5 -0
  140. data/spec/fixtures/listing_carts/empty.json +5 -0
  141. data/spec/fixtures/listing_carts/listing_cart.json +19 -0
  142. data/spec/fixtures/listing_carts/new.json +12 -0
  143. data/spec/fixtures/listing_carts/post.json +10 -0
  144. data/spec/fixtures/listing_carts/remove_listing.json +13 -0
  145. data/spec/fixtures/listings/constraints.json +18 -0
  146. data/spec/fixtures/listings/constraints_with_pagination.json +24 -0
  147. data/spec/fixtures/listings/document_index.json +19 -0
  148. data/spec/fixtures/listings/multiple.json +69 -0
  149. data/spec/fixtures/listings/no_subresources.json +38 -0
  150. data/spec/fixtures/listings/open_houses.json +21 -0
  151. data/spec/fixtures/listings/photos/index.json +469 -0
  152. data/spec/fixtures/listings/photos/new.json +12 -0
  153. data/spec/fixtures/listings/photos/post.json +20 -0
  154. data/spec/fixtures/listings/put.json +5 -0
  155. data/spec/fixtures/listings/put_expiration_date.json +5 -0
  156. data/spec/fixtures/listings/saved_search.json +17 -0
  157. data/spec/fixtures/listings/shared_listing_get.json +14 -0
  158. data/spec/fixtures/listings/shared_listing_new.json +9 -0
  159. data/spec/fixtures/listings/shared_listing_post.json +10 -0
  160. data/spec/fixtures/listings/tour_of_homes.json +23 -0
  161. data/spec/fixtures/listings/videos_index.json +18 -0
  162. data/spec/fixtures/listings/virtual_tours_index.json +42 -0
  163. data/spec/fixtures/listings/with_documents.json +52 -0
  164. data/spec/fixtures/listings/with_permissions.json +44 -0
  165. data/spec/fixtures/listings/with_photos.json +110 -0
  166. data/spec/fixtures/listings/with_supplement.json +39 -0
  167. data/spec/fixtures/listings/with_videos.json +54 -0
  168. data/spec/fixtures/listings/with_vtour.json +48 -0
  169. data/spec/fixtures/logo_fbs.png +0 -0
  170. data/spec/fixtures/messages/new.json +14 -0
  171. data/spec/fixtures/messages/new_empty.json +7 -0
  172. data/spec/fixtures/messages/new_with_recipients.json +15 -0
  173. data/spec/fixtures/messages/post.json +5 -0
  174. data/spec/fixtures/notes/add.json +11 -0
  175. data/spec/fixtures/notes/agent_shared.json +11 -0
  176. data/spec/fixtures/notes/agent_shared_empty.json +7 -0
  177. data/spec/fixtures/notes/new.json +5 -0
  178. data/spec/fixtures/notifications/mark_read.json +1 -0
  179. data/spec/fixtures/notifications/new.json +8 -0
  180. data/spec/fixtures/notifications/new_empty.json +7 -0
  181. data/spec/fixtures/notifications/notifications.json +43 -0
  182. data/spec/fixtures/notifications/post.json +10 -0
  183. data/spec/fixtures/notifications/unread.json +10 -0
  184. data/spec/fixtures/oauth2/access.json +3 -0
  185. data/spec/fixtures/oauth2/access_with_old_refresh.json +5 -0
  186. data/spec/fixtures/oauth2/access_with_refresh.json +5 -0
  187. data/spec/fixtures/oauth2/authorization_code_body.json +7 -0
  188. data/spec/fixtures/oauth2/error.json +3 -0
  189. data/spec/fixtures/oauth2/password_body.json +7 -0
  190. data/spec/fixtures/oauth2/refresh_body.json +7 -0
  191. data/spec/fixtures/oauth2_error.json +3 -0
  192. data/spec/fixtures/property_types/property_types.json +31 -0
  193. data/spec/fixtures/session.json +10 -0
  194. data/spec/fixtures/standardfields/city.json +1031 -0
  195. data/spec/fixtures/standardfields/nearby.json +53 -0
  196. data/spec/fixtures/standardfields/standardfields.json +188 -0
  197. data/spec/fixtures/standardfields/stateorprovince.json +36 -0
  198. data/spec/fixtures/success.json +5 -0
  199. data/spec/json_helper.rb +76 -0
  200. data/spec/mock_helper.rb +124 -0
  201. data/spec/oauth2_helper.rb +68 -0
  202. data/spec/spec_helper.rb +48 -0
  203. data/spec/unit/flexmls_api_spec.rb~ +23 -0
  204. data/spec/unit/spark_api/authentication/api_auth_spec.rb +169 -0
  205. data/spec/unit/spark_api/authentication/api_auth_spec.rb~ +169 -0
  206. data/spec/unit/spark_api/authentication/base_auth_spec.rb +10 -0
  207. data/spec/unit/spark_api/authentication/base_auth_spec.rb~ +10 -0
  208. data/spec/unit/spark_api/authentication/oauth2_impl/grant_type_base_spec.rb +10 -0
  209. data/spec/unit/spark_api/authentication/oauth2_impl/grant_type_base_spec.rb~ +10 -0
  210. data/spec/unit/spark_api/authentication/oauth2_spec.rb +205 -0
  211. data/spec/unit/spark_api/authentication/oauth2_spec.rb~ +205 -0
  212. data/spec/unit/spark_api/authentication_spec.rb +38 -0
  213. data/spec/unit/spark_api/authentication_spec.rb~ +38 -0
  214. data/spec/unit/spark_api/configuration/yaml_spec.rb +72 -0
  215. data/spec/unit/spark_api/configuration/yaml_spec.rb~ +72 -0
  216. data/spec/unit/spark_api/configuration_spec.rb +122 -0
  217. data/spec/unit/spark_api/configuration_spec.rb~ +122 -0
  218. data/spec/unit/spark_api/faraday_spec.rb +90 -0
  219. data/spec/unit/spark_api/faraday_spec.rb~ +90 -0
  220. data/spec/unit/spark_api/models/account_spec.rb +176 -0
  221. data/spec/unit/spark_api/models/base_spec.rb +106 -0
  222. data/spec/unit/spark_api/models/connect_prefs_spec.rb +9 -0
  223. data/spec/unit/spark_api/models/constraint_spec.rb +19 -0
  224. data/spec/unit/spark_api/models/contact_spec.rb +108 -0
  225. data/spec/unit/spark_api/models/contact_spec.rb~ +108 -0
  226. data/spec/unit/spark_api/models/document_spec.rb +32 -0
  227. data/spec/unit/spark_api/models/listing_cart_spec.rb +127 -0
  228. data/spec/unit/spark_api/models/listing_cart_spec.rb~ +127 -0
  229. data/spec/unit/spark_api/models/listing_spec.rb +320 -0
  230. data/spec/unit/spark_api/models/listing_spec.rb~ +320 -0
  231. data/spec/unit/spark_api/models/message_spec.rb +47 -0
  232. data/spec/unit/spark_api/models/message_spec.rb~ +47 -0
  233. data/spec/unit/spark_api/models/note_spec.rb +63 -0
  234. data/spec/unit/spark_api/models/note_spec.rb~ +63 -0
  235. data/spec/unit/spark_api/models/notification_spec.rb +62 -0
  236. data/spec/unit/spark_api/models/notification_spec.rb~ +62 -0
  237. data/spec/unit/spark_api/models/open_house_spec.rb +39 -0
  238. data/spec/unit/spark_api/models/photo_spec.rb +92 -0
  239. data/spec/unit/spark_api/models/property_types_spec.rb +33 -0
  240. data/spec/unit/spark_api/models/saved_search_spec.rb +40 -0
  241. data/spec/unit/spark_api/models/shared_listing_spec.rb +45 -0
  242. data/spec/unit/spark_api/models/shared_listing_spec.rb~ +45 -0
  243. data/spec/unit/spark_api/models/standard_fields_spec.rb +60 -0
  244. data/spec/unit/spark_api/models/system_info_spec.rb +83 -0
  245. data/spec/unit/spark_api/models/tour_of_home_spec.rb +44 -0
  246. data/spec/unit/spark_api/models/video_spec.rb +36 -0
  247. data/spec/unit/spark_api/models/virtual_tour_spec.rb +44 -0
  248. data/spec/unit/spark_api/multi_client_spec.rb +56 -0
  249. data/spec/unit/spark_api/multi_client_spec.rb~ +56 -0
  250. data/spec/unit/spark_api/paginate_spec.rb +224 -0
  251. data/spec/unit/spark_api/paginate_spec.rb~ +224 -0
  252. data/spec/unit/spark_api/primary_array_spec.rb +41 -0
  253. data/spec/unit/spark_api/primary_array_spec.rb~ +41 -0
  254. data/spec/unit/spark_api/request_spec.rb +344 -0
  255. data/spec/unit/spark_api/request_spec.rb~ +344 -0
  256. data/spec/unit/spark_api_spec.rb +23 -0
  257. metadata +725 -0
@@ -0,0 +1,115 @@
1
+ module SparkApi
2
+ module Models
3
+ class Account < Base
4
+ extend Finders
5
+ self.element_name="accounts"
6
+
7
+ SUBELEMENTS = [:emails, :phones, :websites, :addresses, :images]
8
+ attr_accessor :my_account, *SUBELEMENTS
9
+
10
+ def initialize(attributes={})
11
+ @emails = subresource(Email, "Emails", attributes)
12
+ @phones = subresource(Phone, "Phones", attributes)
13
+ @websites = subresource(Website, "Websites", attributes)
14
+ @addresses = subresource(Address, "Addresses", attributes)
15
+ if attributes["Images"]
16
+ @images = []
17
+ attributes["Images"].each { |i| @images << Image.new(i) }
18
+ else
19
+ @images = nil
20
+ end
21
+ @my_account = false
22
+ super(attributes)
23
+ end
24
+
25
+ def self.my(arguments={})
26
+ account = collect(connection.get("/my/account", arguments)).first
27
+ account.my_account = true
28
+ account
29
+ end
30
+
31
+ def my_account?
32
+ @my_account
33
+ end
34
+
35
+ def self.by_office(office_id, arguments={})
36
+ collect(connection.get("#{self.path()}/by/office/#{office_id}", arguments))
37
+ end
38
+
39
+ def primary_img(typ)
40
+ if @images.is_a?(Array)
41
+ matches = @images.select {|i| i.Type == typ}
42
+ matches.sort {|a,b| a.Name <=> b.Name }.first
43
+ else
44
+ nil
45
+ end
46
+ end
47
+
48
+ def save(arguments={})
49
+ self.errors = [] # clear the errors hash
50
+ begin
51
+ return save!(arguments)
52
+ rescue NotFound, BadResourceRequest => e
53
+ self.errors << {:code => e.code, :message => e.message}
54
+ SparkApi.logger.error("Failed to save resource #{self}: #{e.message}")
55
+ end
56
+ false
57
+ end
58
+ def save!(arguments={})
59
+ # The long-term idea is that any setting in the user's account could be updated by including
60
+ # an attribute and calling PUT /my/account, but for now only the GetEmailUpdates attribute
61
+ # is supported
62
+
63
+ save_path = "/accounts/"+self.Id
64
+
65
+ ojbsome = {}
66
+ if attributes['GetEmailUpdates']
67
+ save_path = my_account? ? "/my/account" : self.class.path
68
+ ojbsome["GetEmailUpdates"] = attributes['GetEmailUpdates']
69
+ end
70
+ if attributes['PasswordValidation']
71
+ ojbsome["PasswordValidation"] = attributes['PasswordValidation']
72
+ end
73
+ if attributes['Password']
74
+ ojbsome["Password"] = attributes['Password']
75
+ end
76
+
77
+ results = connection.put save_path, ojbsome, arguments
78
+ true
79
+ end
80
+
81
+
82
+ private
83
+
84
+ def subresource(klass, key, attributes)
85
+ return nil unless attributes.key?(key)
86
+ array = attributes[key]
87
+ result = PrimaryArray.new()
88
+ array.each do |i|
89
+ result << klass.new(i)
90
+ end
91
+ result
92
+ end
93
+
94
+ class Email < Base
95
+ include Primary
96
+ end
97
+
98
+ class Phone < Base
99
+ include Primary
100
+ end
101
+
102
+ class Website < Base
103
+ include Primary
104
+ end
105
+
106
+ class Address < Base
107
+ include Primary
108
+ end
109
+
110
+ class Image < Base
111
+ end
112
+ end
113
+ end
114
+
115
+ end
@@ -0,0 +1,115 @@
1
+ module FlexmlsApi
2
+ module Models
3
+ class Account < Base
4
+ extend Finders
5
+ self.element_name="accounts"
6
+
7
+ SUBELEMENTS = [:emails, :phones, :websites, :addresses, :images]
8
+ attr_accessor :my_account, *SUBELEMENTS
9
+
10
+ def initialize(attributes={})
11
+ @emails = subresource(Email, "Emails", attributes)
12
+ @phones = subresource(Phone, "Phones", attributes)
13
+ @websites = subresource(Website, "Websites", attributes)
14
+ @addresses = subresource(Address, "Addresses", attributes)
15
+ if attributes["Images"]
16
+ @images = []
17
+ attributes["Images"].each { |i| @images << Image.new(i) }
18
+ else
19
+ @images = nil
20
+ end
21
+ @my_account = false
22
+ super(attributes)
23
+ end
24
+
25
+ def self.my(arguments={})
26
+ account = collect(connection.get("/my/account", arguments)).first
27
+ account.my_account = true
28
+ account
29
+ end
30
+
31
+ def my_account?
32
+ @my_account
33
+ end
34
+
35
+ def self.by_office(office_id, arguments={})
36
+ collect(connection.get("#{self.path()}/by/office/#{office_id}", arguments))
37
+ end
38
+
39
+ def primary_img(typ)
40
+ if @images.is_a?(Array)
41
+ matches = @images.select {|i| i.Type == typ}
42
+ matches.sort {|a,b| a.Name <=> b.Name }.first
43
+ else
44
+ nil
45
+ end
46
+ end
47
+
48
+ def save(arguments={})
49
+ self.errors = [] # clear the errors hash
50
+ begin
51
+ return save!(arguments)
52
+ rescue NotFound, BadResourceRequest => e
53
+ self.errors << {:code => e.code, :message => e.message}
54
+ FlexmlsApi.logger.error("Failed to save resource #{self}: #{e.message}")
55
+ end
56
+ false
57
+ end
58
+ def save!(arguments={})
59
+ # The long-term idea is that any setting in the user's account could be updated by including
60
+ # an attribute and calling PUT /my/account, but for now only the GetEmailUpdates attribute
61
+ # is supported
62
+
63
+ save_path = "/accounts/"+self.Id
64
+
65
+ ojbsome = {}
66
+ if attributes['GetEmailUpdates']
67
+ save_path = my_account? ? "/my/account" : self.class.path
68
+ ojbsome["GetEmailUpdates"] = attributes['GetEmailUpdates']
69
+ end
70
+ if attributes['PasswordValidation']
71
+ ojbsome["PasswordValidation"] = attributes['PasswordValidation']
72
+ end
73
+ if attributes['Password']
74
+ ojbsome["Password"] = attributes['Password']
75
+ end
76
+
77
+ results = connection.put save_path, ojbsome, arguments
78
+ true
79
+ end
80
+
81
+
82
+ private
83
+
84
+ def subresource(klass, key, attributes)
85
+ return nil unless attributes.key?(key)
86
+ array = attributes[key]
87
+ result = PrimaryArray.new()
88
+ array.each do |i|
89
+ result << klass.new(i)
90
+ end
91
+ result
92
+ end
93
+
94
+ class Email < Base
95
+ include Primary
96
+ end
97
+
98
+ class Phone < Base
99
+ include Primary
100
+ end
101
+
102
+ class Website < Base
103
+ include Primary
104
+ end
105
+
106
+ class Address < Base
107
+ include Primary
108
+ end
109
+
110
+ class Image < Base
111
+ end
112
+ end
113
+ end
114
+
115
+ end
@@ -0,0 +1,118 @@
1
+ module SparkApi
2
+ module Models
3
+ # =API Model Base class
4
+ # Intended to be a lot like working with ActiveResource, this class adds most of the basic
5
+ # active model type niceties.
6
+ class Base
7
+ extend Paginate
8
+
9
+ attr_accessor :attributes, :errors
10
+ attr_reader :changed
11
+
12
+ # Name of the resource as related to the path name
13
+ def self.element_name
14
+ # TODO I'd love to pull in active model at this point to provide default naming
15
+ @element_name ||= "resource"
16
+ end
17
+
18
+ def self.element_name=(name)
19
+ @element_name = name
20
+ end
21
+
22
+ # Resource path prefix, prepended to the url
23
+ def self.prefix
24
+ @prefix ||= "/"
25
+ end
26
+ def self.prefix=(prefix)
27
+ @prefix = prefix
28
+ end
29
+ def self.path
30
+ "#{prefix}#{element_name}"
31
+ end
32
+
33
+ def self.connection
34
+ SparkApi.client
35
+ end
36
+ def connection
37
+ self.class.connection
38
+ end
39
+
40
+ def initialize(attributes={})
41
+ @attributes = {}
42
+ @errors = []
43
+ @changed = []
44
+ load(attributes)
45
+ end
46
+
47
+ def load(attributes)
48
+ attributes.each do |key,val|
49
+ @attributes[key.to_s] = val
50
+ end
51
+ end
52
+
53
+ def self.get(options={})
54
+ collect(connection.get(path, options))
55
+ end
56
+
57
+ def self.first(options={})
58
+ get(options).first
59
+ end
60
+
61
+ def self.count(options={})
62
+ connection.get(path, options.merge({:_pagination=>"count"}))
63
+ end
64
+
65
+ def method_missing(method_symbol, *arguments)
66
+ method_name = method_symbol.to_s
67
+
68
+ if method_name =~ /(=|\?)$/
69
+ case $1
70
+ when "="
71
+ write_attribute($`, arguments.first)
72
+ # TODO figure out a nice way to present setters for the standard fields
73
+ when "?"
74
+ if attributes.include?($`)
75
+ attributes[$`] ? true : false
76
+ else
77
+ raise NoMethodError
78
+ end
79
+ end
80
+ else
81
+ return attributes[method_name] if attributes.include?(method_name)
82
+ super # GTFO
83
+ end
84
+ end
85
+
86
+ def respond_to?(method_symbol, include_private=false)
87
+ if super
88
+ return true
89
+ else
90
+ method_name = method_symbol.to_s
91
+
92
+ if method_name =~ /=$/
93
+ true
94
+ elsif method_name =~ /(\?)$/
95
+ attributes.include?($`)
96
+ else
97
+ attributes.include?(method_name)
98
+ end
99
+
100
+ end
101
+ end
102
+
103
+ def parse_id(uri)
104
+ uri[/\/.*\/(.+)$/, 1]
105
+ end
106
+
107
+ protected
108
+
109
+ def write_attribute(attribute, value)
110
+ unless attributes[attribute] == value
111
+ attributes[attribute] = value
112
+ @changed << attribute unless @changed.include?(attribute)
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,118 @@
1
+ module FlexmlsApi
2
+ module Models
3
+ # =API Model Base class
4
+ # Intended to be a lot like working with ActiveResource, this class adds most of the basic
5
+ # active model type niceties.
6
+ class Base
7
+ extend Paginate
8
+
9
+ attr_accessor :attributes, :errors
10
+ attr_reader :changed
11
+
12
+ # Name of the resource as related to the path name
13
+ def self.element_name
14
+ # TODO I'd love to pull in active model at this point to provide default naming
15
+ @element_name ||= "resource"
16
+ end
17
+
18
+ def self.element_name=(name)
19
+ @element_name = name
20
+ end
21
+
22
+ # Resource path prefix, prepended to the url
23
+ def self.prefix
24
+ @prefix ||= "/"
25
+ end
26
+ def self.prefix=(prefix)
27
+ @prefix = prefix
28
+ end
29
+ def self.path
30
+ "#{prefix}#{element_name}"
31
+ end
32
+
33
+ def self.connection
34
+ FlexmlsApi.client
35
+ end
36
+ def connection
37
+ self.class.connection
38
+ end
39
+
40
+ def initialize(attributes={})
41
+ @attributes = {}
42
+ @errors = []
43
+ @changed = []
44
+ load(attributes)
45
+ end
46
+
47
+ def load(attributes)
48
+ attributes.each do |key,val|
49
+ @attributes[key.to_s] = val
50
+ end
51
+ end
52
+
53
+ def self.get(options={})
54
+ collect(connection.get(path, options))
55
+ end
56
+
57
+ def self.first(options={})
58
+ get(options).first
59
+ end
60
+
61
+ def self.count(options={})
62
+ connection.get(path, options.merge({:_pagination=>"count"}))
63
+ end
64
+
65
+ def method_missing(method_symbol, *arguments)
66
+ method_name = method_symbol.to_s
67
+
68
+ if method_name =~ /(=|\?)$/
69
+ case $1
70
+ when "="
71
+ write_attribute($`, arguments.first)
72
+ # TODO figure out a nice way to present setters for the standard fields
73
+ when "?"
74
+ if attributes.include?($`)
75
+ attributes[$`] ? true : false
76
+ else
77
+ raise NoMethodError
78
+ end
79
+ end
80
+ else
81
+ return attributes[method_name] if attributes.include?(method_name)
82
+ super # GTFO
83
+ end
84
+ end
85
+
86
+ def respond_to?(method_symbol, include_private=false)
87
+ if super
88
+ return true
89
+ else
90
+ method_name = method_symbol.to_s
91
+
92
+ if method_name =~ /=$/
93
+ true
94
+ elsif method_name =~ /(\?)$/
95
+ attributes.include?($`)
96
+ else
97
+ attributes.include?(method_name)
98
+ end
99
+
100
+ end
101
+ end
102
+
103
+ def parse_id(uri)
104
+ uri[/\/.*\/(.+)$/, 1]
105
+ end
106
+
107
+ protected
108
+
109
+ def write_attribute(attribute, value)
110
+ unless attributes[attribute] == value
111
+ attributes[attribute] = value
112
+ @changed << attribute unless @changed.include?(attribute)
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end