geocaching 0.6.1 → 0.7.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.
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module Geocaching
4
+ class TrackableType
5
+ attr_reader :name
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ end
10
+
11
+ alias :to_s :name
12
+
13
+ def ==(name)
14
+ @name == name
15
+ end
16
+ end
17
+ end
@@ -1,217 +1,25 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "time"
4
-
5
3
  module Geocaching
6
- # The {User} class represents a user on geocaching.com.
7
- #
8
- # == Usage
9
- #
10
- # user = Geocaching::User.fetch(:guid => "...")
11
- # puts user.name #=> "Jack"
12
- #
13
4
  class User
14
- # Creates a new instance and calls the {fetch} method afterwards.
15
- # +:guid+ must be given as an attribute.
16
- #
17
- # @param [Hash] attributes A hash of attributes
18
- # @raise [ArgumentError] No GUID given
19
- # @return [Geocaching::User]
20
- def self.fetch(attributes)
21
- user = new(attributes)
22
- user.fetch
23
- user
24
- end
5
+ attr_accessor :guid
6
+ attr_accessor :name
25
7
 
26
- # Creates a new instance. The following attributes may be specified
27
- # as parameters:
28
- #
29
- # * +:guid+ — The user’s Globally Unique Identifier (GUID)
30
- # * +:name+ — The user‘s name
31
- #
32
- # @param [Hash] attributes A hash of attributes
33
- # @raise [ArgumentError] Trying to set an unknown attribute
34
8
  def initialize(attributes = {})
35
- @data, @doc, @guid = nil, nil, nil
36
-
37
9
  attributes.each do |key, value|
38
- if [:guid, :name].include?(key)
39
- instance_variable_set("@#{key}", value)
40
- else
41
- raise ArgumentError, "Trying to set unknown attribute `#{key}'"
42
- end
43
- end
44
- end
45
-
46
- # Fetches user information from geocaching.com.
47
- #
48
- # @return [void]
49
- # @raise [ArgumentError] No GUID given
50
- def fetch
51
- raise ArgumentError, "No GUID given" unless @guid
52
-
53
- resp, @data = HTTP.get("/profile/?guid=#{guid}")
54
- @doc = Nokogiri::HTML.parse(@data)
55
- end
56
-
57
- # Returns whether user information have successfully been fetched
58
- # from geocaching.com.
59
- #
60
- # @return [Boolean] Have user information been fetched?
61
- def fetched?
62
- @data and @doc
63
- end
64
-
65
- # Returns the user’s Globally Unique Identifier (GUID).
66
- #
67
- # @return [String]
68
- def guid
69
- @guid
70
- end
71
-
72
- # Returns the user’s name.
73
- #
74
- # @return [String]
75
- def name
76
- @name ||= begin
77
- raise NotFetchedError unless fetched?
78
-
79
- elements = @doc.search("#ctl00_ContentBody_lblUserProfile")
80
-
81
- if elements.size == 1 and elements.first.content =~ /Profile for User|Reviewer: (.+)/
82
- HTTP.unescape($1)
10
+ if respond_to?("#{key}=")
11
+ send("#{key}=", value)
83
12
  else
84
- raise ParseError, "Could not extract name from website"
13
+ raise ArgumentError, "Unknown attribute `#{key}'"
85
14
  end
86
15
  end
87
16
  end
88
17
 
89
- # Returns the user’s occupation.
90
- #
91
- # @return [String] Occupation
92
- def occupation
93
- @occupation ||= begin
94
- raise NotFetchedError unless fetched?
95
-
96
- elements = @doc.search("#ctl00_ContentBody_ProfilePanel1_lblOccupationTxt")
97
-
98
- if elements.size == 1
99
- HTTP.unescape(elements.first.content)
100
- else
101
- raise ParseError, "Could not extract occupation from website"
102
- end
103
- end
104
- end
105
-
106
- # Returns the user’s location.
107
- #
108
- # @return [String] Location
109
- def location
110
- @location ||= begin
111
- raise NotFetchedError unless fetched?
112
-
113
- elements = @doc.search("#ctl00_ContentBody_ProfilePanel1_lblLocationTxt")
114
-
115
- if elements.size == 1
116
- HTTP.unescape(elements.first.content)
117
- else
118
- raise ParseError, "Could not extract location from website"
119
- end
120
- end
121
- end
122
-
123
- # Returns the user’s forum title.
124
- #
125
- # @return [String] Forum title
126
- def forum_title
127
- @forum_title ||= begin
128
- raise NotFetchedError unless fetched?
129
-
130
- elements = @doc.search("#ctl00_ContentBody_ProfilePanel1_lblForumTitleTxt")
131
-
132
- if elements.size == 1
133
- HTTP.unescape(elements.first.content)
134
- else
135
- raise ParseError, "Could not extract forum title from website"
136
- end
137
- end
138
- end
139
-
140
- # Returns the user’s homepage.
141
- #
142
- # @return [String] Homepage
143
- def homepage
144
- @homepage ||= begin
145
- raise NotFetchedError unless fetched?
146
-
147
- elements = @doc.search("#ctl00_ContentBody_ProfilePanel1_lnkHomePage")
148
- elements.first["href"] if elements.size == 1
149
- end
150
- end
151
-
152
- # Returns the user’s statuses.
153
- #
154
- # @return [Array<String>] Array of statuses
155
- def status
156
- @status ||= begin
157
- raise NotFetchedError unless fetched?
158
-
159
- elements = @doc.search("#ctl00_ContentBody_ProfilePanel1_lblStatusText")
160
-
161
- if elements.size == 1
162
- HTTP.unescape(elements.first.content).split(",").map(&:strip)
163
- else
164
- raise ParseError, "Could not extract status from website"
165
- end
166
- end
167
- end
168
-
169
- # Returns the user’s last visit date.
170
- #
171
- # @return [Time] Last visit date
172
- def last_visit
173
- @last_visit ||= begin
174
- raise NotFetchedError unless fetched?
175
-
176
- elements = @doc.search("#ctl00_ContentBody_ProfilePanel1_lblLastVisitDate")
177
-
178
- if elements.size == 1
179
- Time.parse(elements.first.content)
180
- else
181
- raise ParseError, "Could not extract last visit date from website"
182
- end
183
- end
184
- end
185
-
186
- # Returns the user’s member since date.
187
- #
188
- # @return [Time] Member since date
189
- def member_since
190
- @member_since ||= begin
191
- raise NotFetchedError unless fetched?
192
-
193
- elements = @doc.search("#ctl00_ContentBody_ProfilePanel1_lblMemberSinceDate")
194
-
195
- if elements.size == 1
196
- Time.parse(elements.first.content)
197
- else
198
- raise ParseError, "Could not extract member since date from website"
199
- end
200
- end
201
- end
202
-
203
- # Returns whether the user is a reviewer.
204
- #
205
- # @return [Boolean] Is user a reviewer?
206
- def reviewer?
207
- status.include?("Reviewer")
208
- end
209
-
210
- # Returns whether the user is a Premium Member.
211
- #
212
- # @return [Boolean] Is user a Premium Member?
213
- def premium_member?
214
- status.include?("Premium Member")
18
+ def to_hash
19
+ {
20
+ :guid => guid,
21
+ :name => name
22
+ }
215
23
  end
216
24
  end
217
25
  end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ module Geocaching
4
+ class Waypoint
5
+ attr_accessor :code
6
+ attr_accessor :name
7
+ attr_accessor :latitude
8
+ attr_accessor :longitude
9
+ attr_accessor :note
10
+ attr_reader :type
11
+ attr_reader :created_at
12
+
13
+ def initialize(attributes = {})
14
+ attributes.each do |key, value|
15
+ if respond_to?("#{key}=")
16
+ send("#{key}=", value)
17
+ else
18
+ raise ArgumentError, "Unknown attribute `#{key}'"
19
+ end
20
+ end
21
+ end
22
+
23
+ def type=(waypoint_type)
24
+ if waypoint_type.kind_of?(Geocaching::WaypointType)
25
+ @type = waypoint_type
26
+ else
27
+ raise TypeError, "`type' must be an instance of Geocaching::WaypointType"
28
+ end
29
+ end
30
+
31
+ def created_at=(time)
32
+ if time.kind_of?(Time)
33
+ @created_at = time
34
+ else
35
+ raise TypeError, "`created_at' must be an instance of Time"
36
+ end
37
+ end
38
+
39
+ def to_hash
40
+ {
41
+ :code => code,
42
+ :name => name,
43
+ :latitude => latitude,
44
+ :longitude => longitude,
45
+ :note => note,
46
+ :type => type,
47
+ :created_at => created_at
48
+ }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module Geocaching
4
+ class WaypointType
5
+ attr_reader :id
6
+
7
+ PARKING_AREA = 0
8
+ QUESTION_TO_ANSWER = 1
9
+ REFERENCE_POINT = 2
10
+ STAGE = 3
11
+ TRAILHEAD = 4
12
+
13
+ MAPPING = [
14
+ [PARKING_AREA, "Parking Area" ],
15
+ [QUESTION_TO_ANSWER, "Question to Answer" ],
16
+ [REFERENCE_POINT, "Reference Point" ],
17
+ [STAGE, "Stages of a Multicache"],
18
+ [TRAILHEAD, "Trailhead" ]
19
+ ]
20
+
21
+ def self.from_name(name)
22
+ if type = MAPPING.find { |_, n| n == name }
23
+ new(type[0])
24
+ end
25
+ end
26
+
27
+ def initialize(id)
28
+ @id = id
29
+ end
30
+
31
+ def name
32
+ @name ||= MAPPING.find { |id, _| id == @id }[1]
33
+ end
34
+
35
+ alias :to_s :name
36
+
37
+ def ==(id)
38
+ @id = id
39
+ end
40
+ end
41
+ end
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geocaching
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 6
8
- - 1
9
- version: 0.6.1
4
+ prerelease:
5
+ version: 0.7.0
10
6
  platform: ruby
11
7
  authors:
12
8
  - Thomas Cyron
@@ -14,7 +10,7 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2011-02-02 00:00:00 +01:00
13
+ date: 2011-04-28 00:00:00 +02:00
18
14
  default_executable:
19
15
  dependencies:
20
16
  - !ruby/object:Gem::Dependency
@@ -25,10 +21,6 @@ dependencies:
25
21
  requirements:
26
22
  - - ">="
27
23
  - !ruby/object:Gem::Version
28
- segments:
29
- - 1
30
- - 4
31
- - 2
32
24
  version: 1.4.2
33
25
  type: :runtime
34
26
  version_requirements: *id001
@@ -40,14 +32,10 @@ dependencies:
40
32
  requirements:
41
33
  - - ">="
42
34
  - !ruby/object:Gem::Version
43
- segments:
44
- - 1
45
- - 4
46
- - 6
47
35
  version: 1.4.6
48
36
  type: :runtime
49
37
  version_requirements: *id002
50
- description: A Ruby library that provides an API for geocaching.com
38
+ description: A Ruby library providing an API for Geocaching.com
51
39
  email: thomas@thcyron.de
52
40
  executables: []
53
41
 
@@ -59,13 +47,25 @@ files:
59
47
  - README.markdown
60
48
  - lib/geocaching/cache.rb
61
49
  - lib/geocaching/cache_type.rb
62
- - lib/geocaching/http.rb
50
+ - lib/geocaching/container_type.rb
51
+ - lib/geocaching/errors.rb
63
52
  - lib/geocaching/log.rb
64
53
  - lib/geocaching/log_type.rb
65
- - lib/geocaching/my_logs.rb
54
+ - lib/geocaching/parsers/cache_gpx.rb
55
+ - lib/geocaching/parsers/cache_gpx_additional_waypoint.rb
56
+ - lib/geocaching/parsers/cache_gpx_cache_waypoint.rb
57
+ - lib/geocaching/parsers/cache_simple.rb
58
+ - lib/geocaching/parsers/log.rb
59
+ - lib/geocaching/parsers/trackable.rb
60
+ - lib/geocaching/session/caches.rb
61
+ - lib/geocaching/session/logs.rb
62
+ - lib/geocaching/session/trackables.rb
63
+ - lib/geocaching/session.rb
64
+ - lib/geocaching/trackable.rb
65
+ - lib/geocaching/trackable_type.rb
66
66
  - lib/geocaching/user.rb
67
- - lib/geocaching/version.rb
68
- - lib/geocaching/watchlist.rb
67
+ - lib/geocaching/waypoint.rb
68
+ - lib/geocaching/waypoint_type.rb
69
69
  - lib/geocaching.rb
70
70
  has_rdoc: false
71
71
  homepage: http://nano.github.com/ruby-geocaching
@@ -81,21 +81,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
81
  requirements:
82
82
  - - ">="
83
83
  - !ruby/object:Gem::Version
84
- segments:
85
- - 0
86
84
  version: "0"
87
85
  required_rubygems_version: !ruby/object:Gem::Requirement
88
86
  none: false
89
87
  requirements:
90
88
  - - ">="
91
89
  - !ruby/object:Gem::Version
92
- segments:
93
- - 0
94
90
  version: "0"
95
91
  requirements: []
96
92
 
97
93
  rubyforge_project:
98
- rubygems_version: 1.3.7
94
+ rubygems_version: 1.5.0
99
95
  signing_key:
100
96
  specification_version: 3
101
97
  summary: Ruby API for geocaching.com
@@ -1,248 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require "cgi"
4
- require "net/http"
5
- require "timeout"
6
-
7
- module Geocaching
8
- # The {HTTP} class handles the HTTP communication with geocaching.com.
9
- class HTTP
10
- # An array of user agent strings. A random one is chosen.
11
- USER_AGENTS = [
12
- "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
13
- "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
14
- "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)",
15
- "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.2) (KHTML, like Gecko)",
16
- "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8",
17
- "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13",
18
- "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10",
19
- "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu)",
20
- "Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00"
21
- ]
22
-
23
- # The user agent sent with each request.
24
- @user_agent = nil
25
-
26
- # Timeout for sending and receiving HTTP data.
27
- @timeout = 8
28
-
29
- class << self
30
- attr_accessor :user_agent, :timeout, :username, :password
31
-
32
- # Returns the singleton instance of this class.
33
- #
34
- # @return [HTTP] Singleton instance of this class
35
- def instance
36
- @instance ||= new
37
- end
38
-
39
- # Alias for:
40
- #
41
- # Geocaching::HTTP.username = username
42
- # Geocaching::HTTP.password = password
43
- # Geocaching::HTTP.instance.login
44
- def login(username = nil, password = nil)
45
- self.username, self.password = username, password if username && password
46
- self.instance.login
47
- end
48
-
49
- # Alias for +Geocaching::HTTP.instance.logout+.
50
- def logout
51
- self.instance.logout
52
- end
53
-
54
- # Alias for +Geocaching::HTTP.instance.loggedin?+.
55
- def loggedin?
56
- self.instance.loggedin?
57
- end
58
-
59
- # Alias for +Geocaching::HTTP.instance.get+.
60
- def get(path)
61
- self.instance.get(path)
62
- end
63
-
64
- # Alias for +Geocaching::HTTP.instance.post+.
65
- def post(path, data = {}, extra_headers = {})
66
- self.instance.post(path, data, extra_headers)
67
- end
68
-
69
- # Converts HTML entities to the corresponding UTF-8 symbols.
70
- #
71
- # @return [String] The converted string
72
- def unescape(str)
73
- str = str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
74
- str = str.gsub(/&#(\d{3});/) { [$1.to_i].pack("U") }
75
- CGI.unescapeHTML(str)
76
- end
77
- end
78
-
79
- # Creates a new instance.
80
- def initialize
81
- @loggedin = false
82
- @cookie = nil
83
- end
84
-
85
- # Logs in into geocaching.com. Username and password need to be set
86
- # before calling this method.
87
- #
88
- # HTTP.username = "username"
89
- # HTTP.password = "password"
90
- #
91
- # @return [void]
92
- # @raise [ArgumentError] Username or password missing
93
- def login
94
- raise ArgumentError, "Missing username" unless self.class.username
95
- raise ArgumentError, "Missing password" unless self.class.password
96
-
97
- raise LoginError, "Already logged in" if @loggedin
98
-
99
- resp, data = post("/login/default.aspx", {
100
- "ctl00$ContentBody$myUsername" => self.class.username,
101
- "ctl00$ContentBody$myPassword" => self.class.password,
102
- "ctl00$ContentBody$Button1" => "Login",
103
- "ctl00$ContentBody$cookie" => "on"
104
- })
105
-
106
- @cookie = resp.response["set-cookie"]
107
- @loggedin = true
108
- end
109
-
110
- # Logs out from geocaching.com.
111
- #
112
- # @return [void]
113
- def logout
114
- raise LoginError, "Not logged in" unless @loggedin
115
-
116
- @loggedin = false
117
- @cookie = nil
118
-
119
- get("/login/default.aspx?RESETCOMPLETE=Y")
120
- end
121
-
122
- # Returns whether you‘ve already logged in.
123
- #
124
- # @return [Boolean] Already logged in?
125
- def loggedin?
126
- @loggedin and @cookie
127
- end
128
-
129
- # Sends a GET request to +path+. The authentication cookie is sent
130
- # with the request if available.
131
- #
132
- # @param [String] path Request path
133
- # @return [Net::HTTP::Response] Reponse object from +Net::HTTP+
134
- # @return [String] Actual content
135
- def get(path)
136
- resp = data = nil
137
- header = default_header
138
- header["Cookie"] = @cookie if @cookie
139
-
140
- begin
141
- Timeout::timeout(self.class.timeout) do
142
- resp, data = http.get(path, header)
143
- end
144
- rescue Timeout::Error
145
- raise TimeoutError, "Timeout hit for GET #{path}"
146
- rescue
147
- raise HTTPError
148
- end
149
-
150
- unless resp.kind_of?(Net::HTTPSuccess)
151
- if resp.kind_of?(Net::HTTPRedirection) and resp.response["location"]
152
- resp, data = get(resp.response["location"])
153
- else
154
- raise HTTPError
155
- end
156
- end
157
-
158
- [resp, data]
159
- end
160
-
161
- # Sends a POST request to +path+ with the data given in the
162
- # +params+ hash. The authentication cookie is sent with the
163
- # request if available.
164
- #
165
- # Before sending the POST request, a GET request is sent to obtain the
166
- # information like +__VIEWPORT+ that are used on geocaching.com to protect
167
- # from Cross Site Request Forgery.
168
- #
169
- # @return [Net::HTTP::Response] Reponse object from +Net::HTTP+
170
- # @return [String] Actual content
171
- # @raise [Geocaching::TimeoutError] Timeout hit
172
- # @raise [Geocaching::HTTPError] HTTP request failed
173
- def post(path, params = {}, extra_headers = {})
174
- if params.kind_of?(Hash)
175
- params = params.merge(metadata(path)).map { |k,v| "#{k}=#{v}" }.join("&")
176
- end
177
-
178
- resp = data = nil
179
-
180
- header = default_header.merge(extra_headers)
181
- header["Cookie"] = @cookie if @cookie
182
-
183
- begin
184
- Timeout::timeout(self.class.timeout) do
185
- resp, data = http.post(path, params, header)
186
- end
187
- rescue Timeout::Error
188
- raise TimeoutError, "Timeout hit for POST #{path}"
189
- rescue
190
- raise HTTPError
191
- end
192
-
193
- unless resp.kind_of?(Net::HTTPSuccess)
194
- if resp.kind_of?(Net::HTTPRedirection) and resp.response["location"]
195
- resp, data = get(resp.response["location"])
196
- else
197
- raise HTTPError
198
- end
199
- end
200
-
201
- [resp, data]
202
- end
203
-
204
- private
205
-
206
- # Sends a GET request to +path+ to obtain form meta data used on
207
- # geocaching.com to protect from CSRF.
208
- #
209
- # @return [Hash] Meta information
210
- def metadata(path)
211
- resp, data = get(path)
212
- meta = {}
213
-
214
- data.scan(/<input type="hidden" name="__([A-Z]+)" id="__[A-Z]+" value="(.*?)" \/>/).each do |match|
215
- meta["__#{match[0]}"] = CGI.escape(match[1])
216
- end
217
-
218
- meta
219
- end
220
-
221
- # Returns the user agent string to use for the HTTP requests. If no
222
- # user agent is set explicitly, a random one is chosen.
223
- #
224
- # @return [String] User agent
225
- def user_agent
226
- self.class.user_agent ||= USER_AGENTS.shuffle.first
227
- end
228
-
229
- # Returns an hash with the HTTP headers sent with each request.
230
- #
231
- # @return [Hash] Default HTTP headers
232
- def default_header
233
- {
234
- "User-Agent" => user_agent
235
- }
236
- end
237
-
238
- # Returns the instance of {Net::HTTP} or creates a new one for
239
- # +www.geocaching.com+.
240
- #
241
- # @return [Net::HTTP]
242
- def http
243
- @http ||= begin
244
- Net::HTTP.new("www.geocaching.com")
245
- end
246
- end
247
- end
248
- end