tagcrumbs 0.3.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 (178) hide show
  1. data/History.txt +9 -0
  2. data/License.txt +22 -0
  3. data/Manifest.txt +177 -0
  4. data/PostInstall.txt +2 -0
  5. data/README.rdoc +45 -0
  6. data/Rakefile +35 -0
  7. data/TODO.txt +17 -0
  8. data/bin/tagcrumbs +5 -0
  9. data/examples/address_update.rb +15 -0
  10. data/examples/comment_new.rb +19 -0
  11. data/examples/favorite_new.rb +17 -0
  12. data/examples/filter_new.rb +15 -0
  13. data/examples/friendship_create.rb +19 -0
  14. data/examples/link_new.rb +16 -0
  15. data/examples/location_update.rb +16 -0
  16. data/examples/picture_update.rb +16 -0
  17. data/examples/placemark_new_simple.rb +24 -0
  18. data/examples/placemark_new_suggestions.rb +24 -0
  19. data/examples/profile_link_new.rb +14 -0
  20. data/examples/profile_update.rb +12 -0
  21. data/examples/request_authorization.rb +25 -0
  22. data/examples/settings_update.rb +12 -0
  23. data/examples/subscription_new.rb +15 -0
  24. data/examples/tagcrumbs_find.rb +25 -0
  25. data/examples/tagcrumbs_search.rb +7 -0
  26. data/examples/user.rb +28 -0
  27. data/examples/user_recommendation_new.rb +15 -0
  28. data/lib/tagcrumbs/builders/builder.rb +45 -0
  29. data/lib/tagcrumbs/builders/json_builder.rb +38 -0
  30. data/lib/tagcrumbs/builders/xml_builder.rb +30 -0
  31. data/lib/tagcrumbs/cli.rb +268 -0
  32. data/lib/tagcrumbs/config_store.rb +35 -0
  33. data/lib/tagcrumbs/exceptions.rb +13 -0
  34. data/lib/tagcrumbs/node.rb +43 -0
  35. data/lib/tagcrumbs/parsers/json_parser.rb +79 -0
  36. data/lib/tagcrumbs/parsers/parser.rb +24 -0
  37. data/lib/tagcrumbs/parsers/xml_parser.rb +54 -0
  38. data/lib/tagcrumbs/proxy.rb +32 -0
  39. data/lib/tagcrumbs/requestor.rb +140 -0
  40. data/lib/tagcrumbs/resources/array.rb +108 -0
  41. data/lib/tagcrumbs/resources/models/accessors.rb +252 -0
  42. data/lib/tagcrumbs/resources/models/activity.rb +19 -0
  43. data/lib/tagcrumbs/resources/models/address.rb +16 -0
  44. data/lib/tagcrumbs/resources/models/city.rb +13 -0
  45. data/lib/tagcrumbs/resources/models/comment.rb +12 -0
  46. data/lib/tagcrumbs/resources/models/country.rb +15 -0
  47. data/lib/tagcrumbs/resources/models/fanship.rb +12 -0
  48. data/lib/tagcrumbs/resources/models/favorite.rb +22 -0
  49. data/lib/tagcrumbs/resources/models/filter.rb +32 -0
  50. data/lib/tagcrumbs/resources/models/flag.rb +10 -0
  51. data/lib/tagcrumbs/resources/models/friendship.rb +12 -0
  52. data/lib/tagcrumbs/resources/models/geoname.rb +8 -0
  53. data/lib/tagcrumbs/resources/models/link.rb +13 -0
  54. data/lib/tagcrumbs/resources/models/location.rb +13 -0
  55. data/lib/tagcrumbs/resources/models/model.rb +148 -0
  56. data/lib/tagcrumbs/resources/models/picture.rb +28 -0
  57. data/lib/tagcrumbs/resources/models/place.rb +17 -0
  58. data/lib/tagcrumbs/resources/models/placemark.rb +30 -0
  59. data/lib/tagcrumbs/resources/models/profile.rb +16 -0
  60. data/lib/tagcrumbs/resources/models/profile_link.rb +12 -0
  61. data/lib/tagcrumbs/resources/models/root.rb +19 -0
  62. data/lib/tagcrumbs/resources/models/settings.rb +14 -0
  63. data/lib/tagcrumbs/resources/models/state.rb +14 -0
  64. data/lib/tagcrumbs/resources/models/subscription.rb +13 -0
  65. data/lib/tagcrumbs/resources/models/suggestions.rb +11 -0
  66. data/lib/tagcrumbs/resources/models/tag.rb +6 -0
  67. data/lib/tagcrumbs/resources/models/tagcrumb.rb +58 -0
  68. data/lib/tagcrumbs/resources/models/user.rb +101 -0
  69. data/lib/tagcrumbs/resources/models/user_recommendation.rb +18 -0
  70. data/lib/tagcrumbs/resources/resource.rb +76 -0
  71. data/lib/tagcrumbs/validations.rb +301 -0
  72. data/lib/tagcrumbs.rb +232 -0
  73. data/script/console +10 -0
  74. data/script/destroy +14 -0
  75. data/script/generate +14 -0
  76. data/spec/fixtures/activity.json +210 -0
  77. data/spec/fixtures/activity.xml +66 -0
  78. data/spec/fixtures/address.json +183 -0
  79. data/spec/fixtures/address.xml +58 -0
  80. data/spec/fixtures/city.json +88 -0
  81. data/spec/fixtures/city.xml +34 -0
  82. data/spec/fixtures/comment.json +286 -0
  83. data/spec/fixtures/comment.xml +87 -0
  84. data/spec/fixtures/country.json +32 -0
  85. data/spec/fixtures/country.xml +13 -0
  86. data/spec/fixtures/fanship.json +180 -0
  87. data/spec/fixtures/fanship.xml +54 -0
  88. data/spec/fixtures/favorite.json +332 -0
  89. data/spec/fixtures/favorite.xml +109 -0
  90. data/spec/fixtures/filter.json +243 -0
  91. data/spec/fixtures/filter.xml +80 -0
  92. data/spec/fixtures/friendship.json +180 -0
  93. data/spec/fixtures/friendship.xml +54 -0
  94. data/spec/fixtures/geoname.json +18 -0
  95. data/spec/fixtures/geoname.xml +6 -0
  96. data/spec/fixtures/json_parser.json +25 -0
  97. data/spec/fixtures/link.json +288 -0
  98. data/spec/fixtures/link.xml +88 -0
  99. data/spec/fixtures/location.json +204 -0
  100. data/spec/fixtures/location.xml +71 -0
  101. data/spec/fixtures/picture.json +154 -0
  102. data/spec/fixtures/picture.png +0 -0
  103. data/spec/fixtures/picture.xml +49 -0
  104. data/spec/fixtures/placemark.json +357 -0
  105. data/spec/fixtures/placemark.xml +58 -0
  106. data/spec/fixtures/placemarks.json +887 -0
  107. data/spec/fixtures/placemarks.xml +348 -0
  108. data/spec/fixtures/profile.json +282 -0
  109. data/spec/fixtures/profile.xml +100 -0
  110. data/spec/fixtures/profile_link.json +156 -0
  111. data/spec/fixtures/profile_link.xml +49 -0
  112. data/spec/fixtures/root.json +46 -0
  113. data/spec/fixtures/root.xml +14 -0
  114. data/spec/fixtures/settings.json +147 -0
  115. data/spec/fixtures/settings.xml +45 -0
  116. data/spec/fixtures/state.json +62 -0
  117. data/spec/fixtures/state.xml +23 -0
  118. data/spec/fixtures/subscription.json +283 -0
  119. data/spec/fixtures/subscription.xml +86 -0
  120. data/spec/fixtures/suggestions.json +1877 -0
  121. data/spec/fixtures/suggestions.xml +724 -0
  122. data/spec/fixtures/tag.json +9 -0
  123. data/spec/fixtures/tag.xml +4 -0
  124. data/spec/fixtures/user.json +105 -0
  125. data/spec/fixtures/user.xml +31 -0
  126. data/spec/fixtures/user_recommendation.json +349 -0
  127. data/spec/fixtures/user_recommendation.xml +106 -0
  128. data/spec/fixtures/validation_errors.json +5 -0
  129. data/spec/fixtures/validation_errors.xml +5 -0
  130. data/spec/fixtures/xml_parser.xml +13 -0
  131. data/spec/spec.opts +1 -0
  132. data/spec/spec_helper.rb +75 -0
  133. data/spec/tagcrumbs/builders/builder_spec.rb +57 -0
  134. data/spec/tagcrumbs/builders/json_builder_spec.rb +47 -0
  135. data/spec/tagcrumbs/builders/xml_builder_spec.rb +34 -0
  136. data/spec/tagcrumbs/exceptions_spec.rb +16 -0
  137. data/spec/tagcrumbs/node_spec.rb +42 -0
  138. data/spec/tagcrumbs/parsers/json_parser_spec.rb +117 -0
  139. data/spec/tagcrumbs/parsers/parser_spec.rb +25 -0
  140. data/spec/tagcrumbs/parsers/xml_parser_spec.rb +117 -0
  141. data/spec/tagcrumbs/proxy_spec.rb +48 -0
  142. data/spec/tagcrumbs/requestor_spec.rb +62 -0
  143. data/spec/tagcrumbs/resources/array_spec.rb +62 -0
  144. data/spec/tagcrumbs/resources/models/accessors_spec.rb +123 -0
  145. data/spec/tagcrumbs/resources/models/activity_spec.rb +33 -0
  146. data/spec/tagcrumbs/resources/models/address_spec.rb +24 -0
  147. data/spec/tagcrumbs/resources/models/city_spec.rb +33 -0
  148. data/spec/tagcrumbs/resources/models/comment_spec.rb +23 -0
  149. data/spec/tagcrumbs/resources/models/country_spec.rb +26 -0
  150. data/spec/tagcrumbs/resources/models/fanship_spec.rb +28 -0
  151. data/spec/tagcrumbs/resources/models/favorite_spec.rb +28 -0
  152. data/spec/tagcrumbs/resources/models/filter_spec.rb +43 -0
  153. data/spec/tagcrumbs/resources/models/flag_spec.rb +5 -0
  154. data/spec/tagcrumbs/resources/models/friendship_spec.rb +28 -0
  155. data/spec/tagcrumbs/resources/models/geoname_spec.rb +18 -0
  156. data/spec/tagcrumbs/resources/models/link_spec.rb +24 -0
  157. data/spec/tagcrumbs/resources/models/location_spec.rb +28 -0
  158. data/spec/tagcrumbs/resources/models/model_spec.rb +27 -0
  159. data/spec/tagcrumbs/resources/models/picture_spec.rb +42 -0
  160. data/spec/tagcrumbs/resources/models/place_spec.rb +12 -0
  161. data/spec/tagcrumbs/resources/models/placemark_spec.rb +61 -0
  162. data/spec/tagcrumbs/resources/models/profile_link_spec.rb +29 -0
  163. data/spec/tagcrumbs/resources/models/profile_spec.rb +43 -0
  164. data/spec/tagcrumbs/resources/models/root_spec.rb +57 -0
  165. data/spec/tagcrumbs/resources/models/settings_spec.rb +32 -0
  166. data/spec/tagcrumbs/resources/models/state_spec.rb +30 -0
  167. data/spec/tagcrumbs/resources/models/subscription_spec.rb +28 -0
  168. data/spec/tagcrumbs/resources/models/suggestions_spec.rb +33 -0
  169. data/spec/tagcrumbs/resources/models/tag_spec.rb +16 -0
  170. data/spec/tagcrumbs/resources/models/tagcrumb_spec.rb +21 -0
  171. data/spec/tagcrumbs/resources/models/user_recommendation_spec.rb +35 -0
  172. data/spec/tagcrumbs/resources/models/user_spec.rb +128 -0
  173. data/spec/tagcrumbs/resources/resource_spec.rb +62 -0
  174. data/spec/tagcrumbs/validations_spec.rb +27 -0
  175. data/spec/tagcrumbs_spec.rb +103 -0
  176. data/tagcrumbs.gemspec +59 -0
  177. data/tasks/rspec.rake +21 -0
  178. metadata +327 -0
@@ -0,0 +1,13 @@
1
+ module Tagcrumbs
2
+ # A Placemark can contain many Links.
3
+ class Link < Model
4
+ can_be :created, :updated, :destroyed
5
+
6
+ writeable_attributes :url, :link_type
7
+ readable_attributes :title, :created_at, :updated_at
8
+
9
+ has_one :tagcrumb, :modifiable => true
10
+
11
+
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Tagcrumbs
2
+ # The current Location of the user. It can only be updated. This location is the default value for all queries that
3
+ # take your current location into account.
4
+ class Location < Model
5
+ can_be :updated
6
+
7
+ writeable_attributes :latitude, :longitude
8
+
9
+ has_one :user
10
+ has_one :city
11
+
12
+ end
13
+ end
@@ -0,0 +1,148 @@
1
+ module Tagcrumbs
2
+ # The base class for all Models that can be read, created, destroyed or updated.
3
+
4
+ class Model < Resource
5
+ include Tagcrumbs::Accessors
6
+ include Validations
7
+
8
+ attr_accessor :new_record
9
+
10
+
11
+ def initialize(attributes ={})
12
+ reset!
13
+
14
+ self.attributes = attributes
15
+ end
16
+
17
+ # Reset the object to a blank state
18
+ def reset!
19
+ super
20
+ self.new_record = true
21
+ @nodes = @nodes_updates = {}
22
+ @errors = Errors.new(self) # reset errors from server
23
+ restore!
24
+
25
+ true
26
+ end
27
+
28
+ # Is this a new record or was it loaded from the web service
29
+ def new_record?
30
+ self.new_record ? true : false
31
+ end
32
+
33
+ # Save the object
34
+ def save
35
+ new_record? ? create : update
36
+ end
37
+
38
+ # Create a new object by posting a representation of the resource to the create_url
39
+ def create
40
+ raise CreateImpossible unless can_be?(:created)
41
+ raise CreateURLMissing unless create_url.present?
42
+ return false unless new_record?
43
+ requestor.post(create_url, to_format)
44
+ handle_save_response
45
+ end
46
+
47
+ # Update an existing object by puting a representation of the resource to the resource_url
48
+ def update
49
+ raise UpdateImpossible unless can_be?(:updated)
50
+ raise ResourceURLMissing unless resource_url.present?
51
+ return false if new_record?
52
+ requestor.put(resource_url, to_format)
53
+ handle_save_response
54
+ end
55
+
56
+ # Remove an existing object from the server by sending a delete request to the server
57
+ def destroy
58
+ raise DestroyImpossible unless can_be?(:destroyed)
59
+ return false if new_record?
60
+
61
+ requestor.delete(resource_url)
62
+
63
+ true
64
+ end
65
+
66
+ # Output the resource in the current active format
67
+ def to_format(format = Tagcrumbs.options[:format], options={})
68
+ case format
69
+ when :xml: to_xml(options)
70
+ when :json: to_json(options)
71
+ end
72
+ end
73
+
74
+ # Return the object in a XML representation
75
+ def to_xml(options = {})
76
+ options.reverse_merge!(:modifiable_only => true)
77
+ Tagcrumbs::XmlBuilder.new(self).build(options)
78
+ end
79
+
80
+ # Return the object in a JSON representation
81
+ def to_json(options = {})
82
+ options.reverse_merge!(:modifiable_only => true, :badgerfish => false)
83
+ Tagcrumbs::JsonBuilder.new(self).build(options)
84
+ end
85
+
86
+
87
+
88
+ # Load the attributes and has_one and has_many associations.
89
+ # The Resource attributes are loaded in the superclass.
90
+ def initialize_from_document(parser, format = Tagcrumbs.options[:format])
91
+ parser = super
92
+
93
+ self.new_record = false
94
+
95
+ if self.loaded? # only if there actually is content
96
+ self.class.attributes.each do |name| # load all attributes
97
+ node = parser.get_node(name)
98
+
99
+ if node
100
+ node_parser = Parser.new_for_format(parser.get_node(name), parser.format)
101
+ self.nodes[name] = Node.new(name, node_parser.get_value, node_parser.get_attributes)
102
+ end
103
+ end
104
+
105
+ self.class.has_one_associations_options.keys.each do |name| # load all has_one associations
106
+ has_one_element = parser.get_node(self.class.has_one_associations_options[name][:node_name])
107
+
108
+ if has_one_element
109
+ has_one_parser = Parser.new_for_format(has_one_element, parser.format)
110
+
111
+ self.has_one_associations[name] = Tagcrumbs.class_by_type(has_one_parser.get_attribute('type')).new_from_document(has_one_element, parser.format)
112
+ end
113
+ end
114
+
115
+ self.class.has_many_associations_options.keys.each do |name| # load all has_many associations
116
+ has_many_element = parser.get_node(self.class.has_many_associations_options[name][:node_name])
117
+
118
+ if has_many_element
119
+ self.has_many_associations[name] = Tagcrumbs::Array.new_from_document(has_many_element, parser.format)
120
+ end
121
+ end
122
+ end
123
+
124
+ parser
125
+ end
126
+
127
+ # Just like new, but directly save the object to the webservice
128
+ def self.create(args={})
129
+ # TODO_SK: test this
130
+ model = new(args)
131
+ model.create
132
+ model
133
+ end
134
+
135
+ private
136
+ # Handle the response after a create or update and set the errors if needed.
137
+ def handle_save_response
138
+ if requestor.response.code == '422'
139
+ errors.from_format(requestor.response.body, requestor.response_format)
140
+ false
141
+ else
142
+ initialize_from_document(requestor.response.body)
143
+ true
144
+ end
145
+ end
146
+
147
+ end
148
+ end
@@ -0,0 +1,28 @@
1
+ module Tagcrumbs
2
+ # Each User has a Picture associated with him/her.
3
+ # There is a default Picture for every user that can only be updated and not destroyed.
4
+ # However, an uploaded Picture of a User can be destroyed which will set the Picture
5
+ # to the default Picture again.
6
+ class Picture < Model
7
+ can_be :updated, :destroyed
8
+
9
+ writeable_attributes :picture_file
10
+ readable_attributes :url, :small_thumbnail_url, :medium_thumbnail_url, :content_type, :created_at, :updated_at
11
+
12
+ has_one :profile
13
+
14
+ # Load a file from the local filesystem and set the attributes.
15
+ # Save the object to upload a new profile picture to the server.
16
+ def get_file(filename)
17
+ return if filename.blank?
18
+
19
+ self.picture_file = {
20
+ :filename => File.basename(filename),
21
+ :mime_type => MIME::Types.type_for(filename).first.content_type,
22
+ :content => Base64.encode64(File.read(filename))
23
+ }
24
+ end
25
+
26
+
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module Tagcrumbs
2
+ # The superclass for City, State and Country
3
+ # All of them contain a name and a permalink.
4
+ # The name is automatically translated into the locale that was set by the user
5
+ # in the settings.
6
+ class Place < Model
7
+ readable_attributes :name, :permalink
8
+
9
+ has_one :geoname
10
+
11
+ def self.search(q, args={})
12
+ args.assert_valid_keys(:page, :per_page, :for)
13
+
14
+ Array.load(Tagcrumbs.root.place_search_url, args.merge(:q => q))
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ module Tagcrumbs
2
+ # The main object in the webservice. A Placemark describes a place on earth.
3
+ # It has many link, comments and can be recommended to your friends.
4
+ class Placemark < Tagcrumb
5
+ can_be :created, :updated, :destroyed
6
+
7
+
8
+ writeable_attributes :name, :notes, :private, :latitude, :longitude, :tag_list, :guess_city, :address_attributes
9
+ readable_attributes :created_at, :updated_at, :short_url, :permalink, :favorites_count
10
+
11
+ has_one :user
12
+ has_one :city, :modifiable => true
13
+ has_one :address
14
+
15
+ has_many :links
16
+ has_many :comments
17
+ has_many :recommendations
18
+
19
+ # Find Placemarks by specifying find criteria.
20
+ def self.find(args={})
21
+ super(args.merge(:tagcrumb_type => :placemark))
22
+ end
23
+
24
+ # Load suggested names, cities and tags that can be shown to the user on the creation of a new Placemark
25
+ def suggestions
26
+ Suggestions.load(Tagcrumbs.current_user.suggestions_url, {:latitude => self.latitude, :longitude => self.longitude}) if self.latitude.present? && self.longitude.present?
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ module Tagcrumbs
2
+ # Each User has Profile. A Profile can only be updated, it is created automatically with a User and destroyed if the User
3
+ # decides to leave Tagcrumbs.
4
+ class Profile < Model
5
+ can_be :updated
6
+
7
+ writeable_attributes :fullname, :about, :description
8
+ readable_attributes :created_at, :updated_at
9
+
10
+ has_one :user
11
+ has_one :city, :modifiable => true
12
+ has_one :picture
13
+
14
+ has_many :profile_links
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module Tagcrumbs
2
+ # Each User can set multiple ProfileLinks
3
+ # e.g. his Facebook account, blog, website etc.
4
+ class ProfileLink < Model
5
+ can_be :created, :updated, :destroyed
6
+
7
+ writeable_attributes :url, :link_type
8
+ readable_attributes :created_at, :updated_at
9
+
10
+ has_one :profile
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ module Tagcrumbs
2
+ # The Root Object that contains links to all other resources on tagcrumbs.com.
3
+ # It is used as the starting point for many other queries.
4
+ class Root < Model
5
+ has_one :you
6
+ has_one :location
7
+
8
+ has_many :tagcrumbs
9
+ has_many :nearby_tagcrumbs
10
+ has_many :countries
11
+
12
+ has_many :popular_countries
13
+ has_many :tags
14
+ has_many :users
15
+
16
+ has_many :search
17
+ has_many :place_search
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module Tagcrumbs
2
+ # Each user has a Settings object that can be updated
3
+ class Settings < Model
4
+ can_be :updated
5
+
6
+ readable_attributes :created_at, :updated_at
7
+ writeable_attributes :locale, :unit_system, :notification_fan, :notification_recommendation, :newsletter, :facebook_new_placemark_feed,
8
+ :facebook_new_favorite_feed, :facebook_new_comment_feed
9
+
10
+
11
+ has_one :user
12
+
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Tagcrumbs
2
+ # A State is a Place and connects Countries and Cities.
3
+ class State < Place
4
+
5
+ has_one :country
6
+ has_many :cities
7
+
8
+ # Search a State by name
9
+ def self.search(q, args={})
10
+ super(q, args.merge(:for => :state))
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Tagcrumbs
2
+ # A Subscription is used to get updates of Placemarks
3
+ class Subscription < Model
4
+ can_be :created, :updated, :destroyed
5
+
6
+ readable_attributes :created_at, :updated_at
7
+
8
+ has_one :user
9
+ has_one :tagcrumb, :modifiable => true
10
+
11
+
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Tagcrumbs
2
+ # Suggestions is a Model that is used to load the name, tag and city suggestions from the web service.
3
+ class Suggestions < Model
4
+ has_many :recommended_tags
5
+ has_many :popular_tags
6
+
7
+ has_many :names
8
+
9
+ has_many :cities
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ module Tagcrumbs
2
+ # A single Tag.
3
+ class Tag < Model
4
+ readable_attributes :name
5
+ end
6
+ end
@@ -0,0 +1,58 @@
1
+ module Tagcrumbs
2
+ # Tagcrumb is the superclass for Placemark and Favorite, they are both a "Tagcrumb" as well
3
+ class Tagcrumb < Model
4
+ # Find Tagcrumbs by specifying filter criteria.
5
+ def self.find(args={})
6
+ args.assert_valid_keys(
7
+ :from, # from: you, friends, fans, recommendations, everybody, user
8
+ :username, # name of the user
9
+ :tags, # comma separates tag list
10
+ :tagcrumb_type, # Placemarks, Favorite or both?
11
+ :city, :state, :country, :middle_of_nowhere, # filter by the place hierarchy
12
+ :within, # within a certain radius
13
+ :latitude, :longitude, # per default within is the current location, can be overwritten with latitude and longitude
14
+ :bbox, # everything between a bounding box
15
+ :since, :until, # filter by time
16
+ :per_page, :page, :sort, :order # filter options
17
+ )
18
+
19
+ Array.load(Tagcrumbs.root.tagcrumbs_url, typecast_and_validate_query_parameters(args))
20
+ end
21
+
22
+ # Use a fulltext search to find Tagcrumbs.
23
+ # This is different from "finding" by filter criteria
24
+ def self.search(args={})
25
+ args.assert_valid_keys(:q, :from, :l, :w, :page, :per_page)
26
+
27
+ Array.load(Tagcrumbs.root.search_url, typecast_and_validate_query_parameters(args))
28
+ end
29
+
30
+
31
+ def self.typecast_and_validate_query_parameters(args)
32
+ query_args = {}
33
+
34
+ args.each do |key, value|
35
+ query_args[key] = case key
36
+ when :from, :w: value.to_sym
37
+ when :tagcrumb_type: value.to_s.capitalize
38
+ when :since, :until: value.iso8601
39
+ else
40
+ value
41
+ end
42
+
43
+ Tagcrumbs.validate(key, query_args[key])
44
+ end
45
+
46
+ query_args
47
+ end
48
+
49
+
50
+ end
51
+ end
52
+
53
+
54
+
55
+
56
+
57
+
58
+
@@ -0,0 +1,101 @@
1
+ module Tagcrumbs
2
+ # The main actor in the webservice.
3
+ class User < Model
4
+ readable_attributes :username, :created_at, :updated_at
5
+
6
+ has_one :profile
7
+ has_one :picture
8
+ has_one :settings
9
+ has_one :location
10
+ has_one :suggestions
11
+
12
+ has_many :tagcrumbs
13
+ has_many :placemarks
14
+ has_many :favorites
15
+
16
+ has_many :profile_links
17
+
18
+ has_many :fanships
19
+ has_many :friendships
20
+
21
+ has_many :recommendations
22
+ has_many :received_recommendations
23
+
24
+ has_many :filters
25
+
26
+ has_many :comments
27
+ has_many :links
28
+ has_many :subscriptions
29
+
30
+ has_many :tags
31
+ has_many :places
32
+
33
+ has_many :activities
34
+
35
+ has_many :tagcrumbs_friends
36
+ has_many :tagcrumbs_fans
37
+
38
+ # An array of all friends of a User (people the user is following)
39
+ def friends
40
+ array = []
41
+
42
+ friendships.each_page do |page|
43
+ array += page.map{|f| f.friend}
44
+ end
45
+
46
+ array
47
+ end
48
+
49
+ # An array of all fans of a User (people that follow this user)
50
+ def fans
51
+ array = []
52
+
53
+ fanships.each_page do |page|
54
+ array += page.map{|f| f.fan}
55
+ end
56
+
57
+ array
58
+ end
59
+
60
+ # The friendship with a specific user
61
+ def friendship_with(user)
62
+ f = Friendship.new
63
+ f.reload("/#{self.username}/friends/#{user}")
64
+ rescue Net::HTTPServerException => error
65
+ f.requestor.response.code == '404' ? nil : (raise error) # not found
66
+ end
67
+
68
+ # Is this user friend with user?
69
+ def friend_with?(user)
70
+ friendship_with(user) ? true : false
71
+ end
72
+
73
+ # The fanship with a specific user
74
+ def fanship_with(user)
75
+ Fanship.load("/#{self.username}/fans/#{user}")
76
+ rescue Net::HTTPServerException => error
77
+ self.requestor.response.code == '404' ? nil : (raise error) # not found
78
+ end
79
+
80
+ # Is this user a fan of user?
81
+ def fan_of?(user)
82
+ fanship_with(user) ? true : false
83
+ end
84
+
85
+
86
+ # Search a User by name or email
87
+ def self.search(q, args={})
88
+ Array.load(Tagcrumbs.root.users_url, args.merge(:u => q))
89
+ end
90
+
91
+ # Load a User by its username
92
+ def self.find_by_username(username)
93
+ User.load("/#{username}")
94
+ end
95
+
96
+ def to_s
97
+ self.username
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,18 @@
1
+ module Tagcrumbs
2
+ # A Recommendation of a Placemark between two Users
3
+ class UserRecommendation < Model
4
+ can_be :created
5
+
6
+ readable_attributes :created_at, :updated_at
7
+ writeable_attributes :message
8
+
9
+ has_one :user
10
+ has_one :tagcrumb, :modifiable => true
11
+ has_one :recommended_user, :modifiable => true
12
+
13
+
14
+ def create_url
15
+ Tagcrumbs.current_user.recommendations_url # has to be overwritten
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,76 @@
1
+ module Tagcrumbs
2
+ # Superclass for all other Resources
3
+ class Resource
4
+ attr_accessor :resource_url, :loaded
5
+ attr_writer :requestor
6
+ attr_reader :properties
7
+
8
+ def initialize
9
+ reset!
10
+ end
11
+
12
+ # Clean up the state of the model and make it blank again
13
+ def reset!
14
+ self.resource_url = nil
15
+ self.loaded = false
16
+ self.properties = {}
17
+
18
+ true
19
+ end
20
+
21
+ # Is the Resource loaded or is it just a stub and the attributes still need to be loaded from the web?
22
+ def loaded?
23
+ self.loaded ? true : false
24
+ end
25
+
26
+ # A requestor that is auto-generated if needed to make requests to the webservice
27
+ def requestor
28
+ @requestor ||= Requestor.new
29
+ end
30
+
31
+ # Reset the Resource, reload the data from the web and initialize it again from the document
32
+ def reload(url = nil)
33
+ self.requestor.get(url || resource_url)
34
+ initialize_from_document(requestor.response.body, requestor.response_format)
35
+ true
36
+ end
37
+
38
+ # Set the properties and automatically set the resource_url
39
+ def properties=(properties)
40
+ self.resource_url = properties['xlink:href'] if properties['xlink:href']
41
+ @properties = properties.with_indifferent_access
42
+ end
43
+
44
+ # Load a Resource from a URL with optional query parameters
45
+ # The correct Resource class is automatically determined.
46
+ def self.load(path, query_string = {}, requestor_options={})
47
+ requestor = Requestor.new(requestor_options)
48
+ requestor.get(path, query_string)
49
+
50
+ resource = new_from_document(requestor.response.body, requestor.response_format)
51
+ end
52
+
53
+ # Create a new Resource from a document.
54
+ # The correct Resource class is automatically determined.
55
+ def self.new_from_document(document, format = Tagcrumbs.options[:format])
56
+ parser = Parser.new_for_format(document, format)
57
+
58
+ resource = Tagcrumbs.class_by_type(parser.get_attribute('type')).new
59
+ resource.initialize_from_document(parser, format)
60
+
61
+ resource
62
+ end
63
+
64
+ # Initialize the object with data from the document
65
+ def initialize_from_document(document, format = Tagcrumbs.options[:format])
66
+ parser = Parser.new_for_format(document, format)
67
+ reset!
68
+
69
+ self.loaded = parser.node_loaded?
70
+ self.properties = parser.get_attributes || {}
71
+
72
+ parser
73
+ end
74
+
75
+ end
76
+ end