reagent-fleakr 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +115 -20
- data/Rakefile +1 -1
- data/lib/fleakr.rb +66 -7
- data/lib/fleakr/api.rb +7 -0
- data/lib/fleakr/api/file_parameter.rb +47 -0
- data/lib/fleakr/api/method_request.rb +57 -0
- data/lib/fleakr/api/parameter.rb +35 -0
- data/lib/fleakr/api/parameter_list.rb +96 -0
- data/lib/fleakr/api/response.rb +2 -2
- data/lib/fleakr/api/upload_request.rb +64 -0
- data/lib/fleakr/api/value_parameter.rb +36 -0
- data/lib/fleakr/core_ext.rb +1 -0
- data/lib/fleakr/core_ext/hash.rb +22 -0
- data/lib/fleakr/objects.rb +9 -0
- data/lib/fleakr/objects/authentication_token.rb +43 -0
- data/lib/fleakr/objects/contact.rb +5 -5
- data/lib/fleakr/objects/error.rb +2 -2
- data/lib/fleakr/objects/group.rb +2 -2
- data/lib/fleakr/objects/image.rb +7 -7
- data/lib/fleakr/objects/photo.rb +69 -5
- data/lib/fleakr/objects/search.rb +3 -6
- data/lib/fleakr/objects/set.rb +11 -5
- data/lib/fleakr/objects/user.rb +14 -26
- data/lib/fleakr/support.rb +2 -0
- data/lib/fleakr/support/attribute.rb +30 -12
- data/lib/fleakr/support/object.rb +20 -4
- data/lib/fleakr/version.rb +1 -1
- data/test/fixtures/auth.checkToken.xml +8 -0
- data/test/fixtures/auth.getFullToken.xml +8 -0
- data/test/fixtures/people.getInfo.xml +1 -1
- data/test/fixtures/photos.getInfo.xml +20 -0
- data/test/test_helper.rb +18 -3
- data/test/unit/fleakr/api/file_parameter_test.rb +63 -0
- data/test/unit/fleakr/api/method_request_test.rb +103 -0
- data/test/unit/fleakr/api/parameter_list_test.rb +161 -0
- data/test/unit/fleakr/api/parameter_test.rb +34 -0
- data/test/unit/fleakr/api/upload_request_test.rb +133 -0
- data/test/unit/fleakr/api/value_parameter_test.rb +41 -0
- data/test/unit/fleakr/core_ext/hash_test.rb +32 -0
- data/test/unit/fleakr/objects/authentication_token_test.rb +47 -0
- data/test/unit/fleakr/objects/image_test.rb +10 -5
- data/test/unit/fleakr/objects/photo_test.rb +96 -36
- data/test/unit/fleakr/objects/search_test.rb +1 -1
- data/test/unit/fleakr/objects/set_test.rb +12 -1
- data/test/unit/fleakr/objects/user_test.rb +2 -16
- data/test/unit/fleakr/support/attribute_test.rb +82 -24
- data/test/unit/fleakr/support/object_test.rb +26 -3
- data/test/unit/fleakr_test.rb +65 -6
- metadata +27 -4
- data/lib/fleakr/api/request.rb +0 -58
- data/test/unit/fleakr/api/request_test.rb +0 -93
data/README.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
== Description
|
4
4
|
|
5
|
-
A
|
5
|
+
A small, yet powerful, gem to interface with Flickr photostreams
|
6
6
|
|
7
7
|
== Installation
|
8
8
|
|
@@ -22,16 +22,24 @@ Or ...
|
|
22
22
|
|
23
23
|
== Usage
|
24
24
|
|
25
|
-
|
25
|
+
To get started, you'll need to grab an API key from Flickr to at least perform any of
|
26
|
+
the non-authenticated, read-only calls. Head on over to the Flickr site to grab one, I'll
|
27
|
+
be here when you get back: http://www.flickr.com/services/api/misc.api_keys.html
|
26
28
|
|
27
|
-
|
28
|
-
>> require 'fleakr'
|
29
|
+
Now that you have your key, you can get things rolling with irb and the fleakr gem:
|
29
30
|
|
31
|
+
$ irb -r rubygems
|
32
|
+
>> require 'fleakr'
|
33
|
+
|
30
34
|
Then, set your API key (only need to do this once per session):
|
31
35
|
|
32
36
|
>> Fleakr.api_key = '<your api key here>'
|
33
|
-
|
34
|
-
|
37
|
+
|
38
|
+
=== A Brief Tour
|
39
|
+
|
40
|
+
With just an API key, you have the ability to retrieve a substantial amount of data
|
41
|
+
about users, their photosets, photos, contacts, and groups. Let's start by finding a
|
42
|
+
user by his username:
|
35
43
|
|
36
44
|
>> user = Fleakr.user('the decapitator')
|
37
45
|
=> #<Fleakr::Objects::User:0x692648 @username="the decapitator", @id="21775151@N06">
|
@@ -47,13 +55,18 @@ Once you have a user, you can find his associated sets:
|
|
47
55
|
=> [#<Fleakr::Objects::Set:0x671358 @title="The Decapitator", @description="">,
|
48
56
|
#<Fleakr::Objects::Set:0x66d898 @title="londonpaper hijack", ...
|
49
57
|
|
58
|
+
His individual photos:
|
59
|
+
|
60
|
+
>> user.photos.first
|
61
|
+
=> #<Fleakr::Objects::Photo:0x161b024 @title="\"Be Fabulous\"" ... >
|
62
|
+
|
50
63
|
Or contacts:
|
51
64
|
|
52
65
|
>> user.contacts.first
|
53
66
|
=> #<Fleakr::Objects::User:0x19039bc @username=".schill",
|
54
67
|
@id="12289718@N00", @icon_farm="1", @icon_server="4">
|
55
68
|
|
56
|
-
Or groups if you would like:
|
69
|
+
Or his groups if you would like:
|
57
70
|
|
58
71
|
>> user.groups
|
59
72
|
=> [#<Fleakr::Objects::Group:0x11f2330 ...,
|
@@ -65,7 +78,7 @@ Or groups if you would like:
|
|
65
78
|
|
66
79
|
Groups also contain photos:
|
67
80
|
|
68
|
-
>>
|
81
|
+
>> user.groups.last.photos.first.title
|
69
82
|
=> "Welcome To The Machine"
|
70
83
|
|
71
84
|
When accessing a set, you can also grab all the photos that are in that set:
|
@@ -77,20 +90,59 @@ When accessing a set, you can also grab all the photos that are in that set:
|
|
77
90
|
>> user.sets.first.photos.first.title
|
78
91
|
=> "Untitled1"
|
79
92
|
|
93
|
+
=== Photos
|
94
|
+
|
95
|
+
Each photo object contains metadata about a collection of images, each representing different
|
96
|
+
sizes. Once we have a single photo:
|
97
|
+
|
98
|
+
>> photo = user.photos.first
|
99
|
+
=> #<Fleakr::Objects::Photo:0x161b024 @title="\"Be Fabulous\"" ... >
|
100
|
+
|
101
|
+
We can get information about one of the sizes:
|
102
|
+
|
103
|
+
>> photo.small
|
104
|
+
=> #<Fleakr::Objects::Image:0x1768f1c @height="172", @size="Small", @width="240",
|
105
|
+
@url="http://farm4.static.flickr.com/3250/2924549350_cbc1804258_m.jpg",
|
106
|
+
@page="http://www.flickr.com/photos/the_decapitator/2924549350/sizes/s/">
|
107
|
+
|
108
|
+
Grab the URL for the image itself:
|
109
|
+
|
110
|
+
>> photo.small.url
|
111
|
+
=> "http://farm4.static.flickr.com/3250/2924549350_cbc1804258_m.jpg"
|
112
|
+
|
113
|
+
Or grab the URL for its page on the Flickr site:
|
114
|
+
|
115
|
+
>> photo.small.page
|
116
|
+
=> "http://www.flickr.com/photos/the_decapitator/2924549350/sizes/s/"
|
117
|
+
|
118
|
+
Other sizes are available (:square, :thumbnail, :small, :medium, :large, :original) and
|
119
|
+
are accessed in the same way:
|
120
|
+
|
121
|
+
>> photo.original.url
|
122
|
+
=> "http://farm4.static.flickr.com/3250/2924549350_1cf67c2d47_o.jpg"
|
123
|
+
|
124
|
+
=== Saving Images
|
125
|
+
|
80
126
|
If a photo interests you, save it down to a directory of your choosing:
|
81
127
|
|
82
|
-
>>
|
83
|
-
=> #<File:/tmp/
|
128
|
+
>> photo.original.save_to('/tmp')
|
129
|
+
=> #<File:/tmp/2924549350_1cf67c2d47_o.jpg (closed)>
|
84
130
|
|
85
|
-
|
86
|
-
|
131
|
+
Similarly, you can save down entire sets. Just specify the target directory and the size
|
132
|
+
of the images you're interested in:
|
87
133
|
|
88
134
|
>> user.sets.first.save_to('/tmp', :square)
|
89
135
|
=> [#<Fleakr::Objects::Photo:0x1187a1c @secret="715587b2cb" ...
|
136
|
+
|
137
|
+
This creates a subdirectory within the target directory based on the set's name and preserves
|
138
|
+
the original order of the photos:
|
139
|
+
|
90
140
|
>> Dir["/tmp/#{user.sets.first.title}/*.jpg"].map
|
91
|
-
=> ["/tmp/The Decapitator/
|
92
|
-
"/tmp/The Decapitator/
|
93
|
-
"/tmp/The Decapitator/
|
141
|
+
=> ["/tmp/The Decapitator/01_2117922283_715587b2cb_s.jpg",
|
142
|
+
"/tmp/The Decapitator/02_2125604584_9c09348fd6_s.jpg",
|
143
|
+
"/tmp/The Decapitator/03_2118696542_8af5763bde_s.jpg", ... ]
|
144
|
+
|
145
|
+
=== Searching
|
94
146
|
|
95
147
|
If you would prefer to just search photos, you can do that with search text:
|
96
148
|
|
@@ -116,13 +168,56 @@ Searches can also be scoped to other entities in the system (namely Users and Gr
|
|
116
168
|
>> user.search('serpent')
|
117
169
|
=> [#<Fleakr::Objects::Photo:0x18a6960 @server_id="41", @id="81370156",
|
118
170
|
@farm_id="1", @title="Clear and Serpent Danger", @secret="013091582a">]
|
119
|
-
|
120
|
-
== TODO
|
121
171
|
|
122
|
-
|
172
|
+
=== Authenticated Calls & Uploads
|
173
|
+
|
174
|
+
While read-only access to the API gets you quite a bit of data, you'll need to generate an
|
175
|
+
authentication token if you want access to the more powerful features (like uploading your
|
176
|
+
own photos).
|
177
|
+
|
178
|
+
Assuming you've already applied for a key, go back and make sure you have the right settings
|
179
|
+
to get your auth token. Click on the 'Edit key details' link and ensure that:
|
180
|
+
|
181
|
+
1. Your application description and notes are up-to-date
|
182
|
+
1. The value for 'Authentication Type' is set to 'Mobile Application'
|
183
|
+
1. The value for 'Mobile Permissions' is set to either 'write' or 'delete'
|
184
|
+
|
185
|
+
Once this is set, you'll see your Authentication URL on the key details page (it will look
|
186
|
+
something like http://www.flickr.com/auth-534525246245). Paste this URL into your browser and
|
187
|
+
confirm access to get your mini-token. Now you're ready to make authenticated requests:
|
188
|
+
|
189
|
+
require 'rubygems'
|
190
|
+
require 'fleakr'
|
191
|
+
|
192
|
+
Fleakr.api_key = 'ABC123'
|
193
|
+
Fleakr.shared_secret = 'sekrit' # Available with your key details on the Flickr site
|
194
|
+
Fleakr.mini_token = '362-133-214'
|
195
|
+
|
196
|
+
Fleakr.upload('/path/to/my/photo.jpg')
|
197
|
+
Fleakr.token.value # => "34132412341235-12341234ef34"
|
198
|
+
|
199
|
+
Once you use the mini-token once, it is no longer available. To use the generated auth_token
|
200
|
+
for future requests, just set Fleakr.auth_token to the generated value.
|
201
|
+
|
202
|
+
== Roadmap / TODO
|
203
|
+
|
204
|
+
=== 0.4.x
|
205
|
+
|
206
|
+
* Allow passing of parameters to file uploads to allow for access control / naming
|
207
|
+
* Implement remaining bits of person and photo-related API calls (read-only)
|
208
|
+
* Automatically sign all calls (if we have a secret), authenticate all calls (if we have a token)
|
209
|
+
|
210
|
+
=== 0.5.x
|
211
|
+
|
212
|
+
* Implement asynchronous file upload / replacement w/ ticket checking
|
123
213
|
* Provide a better searching interface
|
124
|
-
|
125
|
-
|
214
|
+
|
215
|
+
=== Future
|
216
|
+
|
217
|
+
* Implement save-able search results (e.g. Fleakr.search('ponies').save_to('/path', :medium))
|
218
|
+
* Implement deeper associations for core elements (e.g. tags / etc..)
|
219
|
+
* Implement write methods for photos & photosets
|
220
|
+
|
126
221
|
== License
|
127
222
|
|
128
223
|
Copyright (c) 2008 Patrick Reagan (reaganpr@gmail.com)
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ spec = Gem::Specification.new do |s|
|
|
12
12
|
s.has_rdoc = true
|
13
13
|
s.extra_rdoc_files = %w(README.rdoc)
|
14
14
|
s.rdoc_options = %w(--main README.rdoc)
|
15
|
-
s.summary = "A
|
15
|
+
s.summary = "A small, yet powerful, gem to interface with Flickr photostreams"
|
16
16
|
s.author = 'Patrick Reagan'
|
17
17
|
s.email = 'reaganpr@gmail.com'
|
18
18
|
s.homepage = 'http://sneaq.net'
|
data/lib/fleakr.rb
CHANGED
@@ -6,13 +6,16 @@ require 'net/http'
|
|
6
6
|
require 'rubygems'
|
7
7
|
require 'hpricot'
|
8
8
|
require 'activesupport'
|
9
|
+
require 'md5'
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
require 'fleakr/api'
|
12
|
+
require 'fleakr/core_ext'
|
13
|
+
require 'fleakr/support'
|
14
|
+
require 'fleakr/objects'
|
14
15
|
|
15
|
-
# = Fleakr: A
|
16
|
+
# = Fleakr: A small, yet powerful, gem to interface with Flickr photostreams
|
17
|
+
#
|
18
|
+
# == Quick Start
|
16
19
|
#
|
17
20
|
# Getting started is easy, just make sure you have a valid API key from Flickr and you can
|
18
21
|
# then start making any non-authenticated request to pull back data for yours and others'
|
@@ -36,10 +39,42 @@ end
|
|
36
39
|
# user.groups
|
37
40
|
#
|
38
41
|
# To see what other associations and attributes are available, see the Fleakr::Objects::User class
|
42
|
+
#
|
43
|
+
# == Authentication
|
44
|
+
#
|
45
|
+
# If you want to do something more than just retrieve public photos (like upload your own),
|
46
|
+
# you'll need to generate an authentication token to use across requests and sessions.
|
47
|
+
#
|
48
|
+
# Assuming you've already applied for a key, go back and make sure you have the right settings
|
49
|
+
# to get your auth token. Click on the 'Edit key details' link and ensure that:
|
50
|
+
#
|
51
|
+
# 1. Your application description and notes are up-to-date
|
52
|
+
# 1. The value for 'Authentication Type' is set to 'Mobile Application'
|
53
|
+
# 1. The value for 'Mobile Permissions' is set to either 'write' or 'delete'
|
54
|
+
#
|
55
|
+
# Once this is set, you'll see your Authentication URL on the key details page (it will look
|
56
|
+
# something like http://www.flickr.com/auth-534525246245). Paste this URL into your browser and
|
57
|
+
# confirm access to get your mini-token. Now you're ready to make authenticated requests:
|
58
|
+
#
|
59
|
+
# require 'rubygems'
|
60
|
+
# require 'fleakr'
|
61
|
+
#
|
62
|
+
# Fleakr.api_key = 'ABC123'
|
63
|
+
# Fleakr.shared_secret = 'sekrit' # Available with your key details on the Flickr site
|
64
|
+
# Fleakr.mini_token = '362-133-214'
|
65
|
+
#
|
66
|
+
# Fleakr.upload('/path/to/my/photo.jpg')
|
67
|
+
# Fleakr.token.value # => "34132412341235-12341234ef34"
|
68
|
+
#
|
69
|
+
# Once you use the mini-token once, it is no longer available. To use the generated auth_token
|
70
|
+
# for future requests, just set Fleakr.auth_token to the generated value.
|
39
71
|
#
|
40
72
|
module Fleakr
|
41
73
|
|
42
|
-
|
74
|
+
# Generic catch-all exception for any API errors
|
75
|
+
class ApiError < StandardError; end
|
76
|
+
|
77
|
+
mattr_accessor :api_key, :shared_secret, :mini_token, :auth_token
|
43
78
|
|
44
79
|
# Find a user based on some unique user data. This method will try to find
|
45
80
|
# the user based on username and will fall back to email if that fails. Example:
|
@@ -51,7 +86,7 @@ module Fleakr
|
|
51
86
|
def self.user(user_data)
|
52
87
|
begin
|
53
88
|
Objects::User.find_by_username(user_data)
|
54
|
-
rescue
|
89
|
+
rescue ApiError
|
55
90
|
Objects::User.find_by_email(user_data)
|
56
91
|
end
|
57
92
|
end
|
@@ -71,4 +106,28 @@ module Fleakr
|
|
71
106
|
Objects::Search.new(params).results
|
72
107
|
end
|
73
108
|
|
109
|
+
# Upload one or more files to your Flickr account (requires authentication). Simply provide
|
110
|
+
# a filename or a pattern to upload one or more files:
|
111
|
+
#
|
112
|
+
# Fleakr.upload('/path/to/my/mug.jpg')
|
113
|
+
# Fleakr.upload('/User/Pictures/Party/*.jpg')
|
114
|
+
#
|
115
|
+
def self.upload(glob)
|
116
|
+
Dir[glob].each {|file| Fleakr::Objects::Photo.upload(file) }
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get the authentication token needed for authenticated requests. Will either use
|
120
|
+
# a valid auth_token (if available) or a mini-token to generate the auth_token.
|
121
|
+
#
|
122
|
+
def self.token
|
123
|
+
@token ||= begin
|
124
|
+
if !Fleakr.auth_token.nil?
|
125
|
+
Fleakr::Objects::AuthenticationToken.from_auth_token(Fleakr.auth_token)
|
126
|
+
else
|
127
|
+
Fleakr::Objects::AuthenticationToken.from_mini_token(Fleakr.mini_token)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
74
133
|
end
|
data/lib/fleakr/api.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Api # :nodoc:
|
3
|
+
|
4
|
+
# = FileParameter
|
5
|
+
#
|
6
|
+
# Parameter class to encapsulate file data sent to the Flickr upload API
|
7
|
+
#
|
8
|
+
class FileParameter < Parameter
|
9
|
+
|
10
|
+
MIME_TYPES = {
|
11
|
+
'.jpg' => 'image/jpeg',
|
12
|
+
'.png' => 'image/png',
|
13
|
+
'.gif' => 'image/gif'
|
14
|
+
}
|
15
|
+
|
16
|
+
# Create a parameter with name and specified filename
|
17
|
+
#
|
18
|
+
def initialize(name, filename)
|
19
|
+
@filename = filename
|
20
|
+
super(name, false)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Discover MIME type by file extension using MIME_TYPES constant
|
24
|
+
#
|
25
|
+
def mime_type
|
26
|
+
MIME_TYPES[File.extname(@filename)]
|
27
|
+
end
|
28
|
+
|
29
|
+
# File data (from @filename) to pass to the Flickr API
|
30
|
+
#
|
31
|
+
def value
|
32
|
+
@value ||= File.read(@filename)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Generate a form representation of this file for upload (as multipart/form-data)
|
36
|
+
#
|
37
|
+
def to_form
|
38
|
+
"Content-Disposition: form-data; name=\"#{self.name}\"; filename=\"#{@filename}\"\r\n" +
|
39
|
+
"Content-Type: #{self.mime_type}\r\n" +
|
40
|
+
"\r\n" +
|
41
|
+
"#{self.value}\r\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Api # :nodoc:
|
3
|
+
|
4
|
+
class MethodRequest
|
5
|
+
attr_reader :parameters, :method
|
6
|
+
|
7
|
+
# Makes a request to the Flickr API and returns a valid Response object. If
|
8
|
+
# there are errors on the response it will raise an ApiError exception. See
|
9
|
+
# #Fleakr::Api::MethodRequest.new for details about the additional parameters
|
10
|
+
#
|
11
|
+
def self.with_response!(method, additional_parameters = {})
|
12
|
+
request = self.new(method, additional_parameters)
|
13
|
+
response = request.send
|
14
|
+
|
15
|
+
raise(Fleakr::ApiError, "Code: #{response.error.code} - #{response.error.message}") if response.error?
|
16
|
+
|
17
|
+
response
|
18
|
+
end
|
19
|
+
|
20
|
+
# Create a new request for the specified API method and pass along any additional
|
21
|
+
# parameters. The Flickr API uses namespacing for its methods - this is optional
|
22
|
+
# when calling this method.
|
23
|
+
#
|
24
|
+
# This must be called after initializing the library with the required API key
|
25
|
+
# see (#Fleakr.api_key=)
|
26
|
+
#
|
27
|
+
# The <tt>additional_parameters</tt> is a list of parameters to pass directly to
|
28
|
+
# the Flickr API call. Exceptions to this are the <tt>:sign?</tt> and
|
29
|
+
# <tt>:authenticate?</tt> options that determine if the call should be signed or
|
30
|
+
# authenticated.
|
31
|
+
#
|
32
|
+
def initialize(method, additional_parameters = {})
|
33
|
+
@parameters = ParameterList.new(additional_parameters)
|
34
|
+
|
35
|
+
self.method = method
|
36
|
+
end
|
37
|
+
|
38
|
+
def method=(method) # :nodoc:
|
39
|
+
@method = method.sub(/^(flickr\.)?/, 'flickr.')
|
40
|
+
@parameters << ValueParameter.new('method', @method)
|
41
|
+
end
|
42
|
+
|
43
|
+
def send # :nodoc:
|
44
|
+
Response.new(Net::HTTP.get(endpoint_uri))
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def endpoint_uri
|
49
|
+
uri = URI.parse('http://api.flickr.com/services/rest/')
|
50
|
+
uri.query = self.parameters.to_query
|
51
|
+
uri
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Api # :nodoc:
|
3
|
+
|
4
|
+
# = Parameter
|
5
|
+
#
|
6
|
+
# Base class for other parameters that get passed to the Flickr API - see
|
7
|
+
# #FileParameter and #ValueParameter for examples
|
8
|
+
#
|
9
|
+
class Parameter
|
10
|
+
|
11
|
+
attr_reader :name
|
12
|
+
|
13
|
+
# A new named parameter (never used directly)
|
14
|
+
#
|
15
|
+
def initialize(name, include_in_signature = true)
|
16
|
+
@name = name
|
17
|
+
@include_in_signature = include_in_signature
|
18
|
+
end
|
19
|
+
|
20
|
+
# Should this parameter be used when generating the signature?
|
21
|
+
#
|
22
|
+
def include_in_signature?
|
23
|
+
(@include_in_signature == true) ? true : false
|
24
|
+
end
|
25
|
+
|
26
|
+
# Used for sorting when generating a signature
|
27
|
+
#
|
28
|
+
def <=>(other)
|
29
|
+
self.name <=> other.name
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|