referee 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ 0.4.0 (Aug. 26, 2010)
2
+ - inital re-release
data/LICENSE ADDED
@@ -0,0 +1,6 @@
1
+ Referee is licensed under the
2
+ Creative Commons Share-Alike
3
+ 3.0 license. <http://is.gd/eF8mg>
4
+
5
+ HTTParty Icebox is under
6
+ the GPL license.
data/Manifest ADDED
@@ -0,0 +1,10 @@
1
+ CHANGELOG
2
+ LICENSE
3
+ Manifest
4
+ README.rdoc
5
+ Rakefile
6
+ lib/referee.rb
7
+ lib/referee/httparty/icebox.rb
8
+ lib/referee/player.rb
9
+ lib/referee/shot.rb
10
+ referee.gemspec
data/README.rdoc ADDED
@@ -0,0 +1,41 @@
1
+ = Referee.
2
+
3
+ Referee is an easy way to communicate with the Dribbble API.
4
+
5
+ == Installation
6
+
7
+ (sudo) gem install httparty referee
8
+
9
+ == Usage
10
+
11
+ Use Referee as a class. For example.
12
+
13
+ player = Referee::Player.info(42)
14
+ puts player['name'] #=> Jeffrey Zeldman
15
+
16
+ It's that easy.
17
+
18
+ == Method List
19
+
20
+ Anything in curly brackets ({}) are optional.
21
+
22
+ === Shots
23
+
24
+ Referee::Shot.info(id) #=> Returns the information about the given shot.
25
+ Referee::Shot.list(id{, :page => #, :per_page => #}) #=> Returns one of the special lists (everyone, debut, popular). Supports pagination.
26
+
27
+ === Players
28
+
29
+ Referee::Player.shots(id{, :page => #, :per_page => #}) #=> Returns the latest shots from the given player. Supports pagination.
30
+ Referee::Player.shots_from_following(id{, :page => #, :per_page => #}) # => Returns the latest shots from the players the given player is following. Supports pagination.
31
+ Referee::Player.info(id) #=> Returns information about the given player.
32
+ Referee::Player.followers(id) #=> Returns a list of players that are following the given player.
33
+ Referee::Player.following(id) #=> Returns a list of players that the given player are following.
34
+ Referee::Player.drafted(id) #=> Returns a list of players that the given player drafted.
35
+
36
+ == Attributes
37
+
38
+ To get any attributes from a method, just use standard JSON object parsing.
39
+
40
+ zeldman = Referee::Player.info(42)
41
+ zeldman['name'] #=> Jeffrey Zeldman
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ ### Referee.
2
+ ### file: Rakefile
3
+
4
+ require 'rubygems'
5
+ require 'rake'
6
+ require 'echoe'
7
+
8
+ Echoe.new('referee', '0.4.0') do |p|
9
+ p.description = 'An easy way to communicate with the Dribbble API.'
10
+ p.summary = 'A Ruby wrapper for the Dribbble API.'
11
+ p.url = 'http://github.com/eturk/referee'
12
+ p.author = 'Ethan Turkeltaub'
13
+ p.email = 'ethan.turkeltaub@gmail.com'
14
+ p.ignore_pattern = []
15
+ p.development_dependencies = ['httparty >=0.6.1']
16
+ end
@@ -0,0 +1,259 @@
1
+ # = Icebox : Caching for HTTParty
2
+ #
3
+ # Cache responses in HTTParty models [http://github.com/jnunemaker/httparty]
4
+ #
5
+ # === Usage
6
+ #
7
+ # class Foo
8
+ # include HTTParty
9
+ # include HTTParty::Icebox
10
+ # cache :store => 'file', :timeout => 600, :location => MY_APP_ROOT.join('tmp', 'cache')
11
+ # end
12
+ #
13
+ # Modeled after Martyn Loughran's APICache [http://github.com/newbamboo/api_cache]
14
+ # and Ruby On Rails's caching [http://api.rubyonrails.org/classes/ActiveSupport/Cache.html]
15
+ #
16
+ # Author: Karel Minarik [www.karmi.cz]
17
+ #
18
+ # === Notes
19
+ #
20
+ # Thanks to Amit Chakradeo to point out objects have to be stored marhalled on FS
21
+ # Thanks to Marlin Forbes to point out query parameters have to be include in the cache key
22
+ #
23
+ #
24
+
25
+ require 'logger'
26
+ require 'ftools'
27
+ require 'tmpdir'
28
+ require 'pathname'
29
+ require 'digest/md5'
30
+
31
+ module HTTParty #:nodoc:
32
+ module Icebox
33
+
34
+ module ClassMethods
35
+
36
+ # Enable caching and set cache options
37
+ # Returns memoized cache object
38
+ #
39
+ # Following options are available, default values are in []:
40
+ #
41
+ # +store+:: Storage mechanism for cached data (memory, filesystem, your own) [memory]
42
+ # +timeout+:: Cache expiration in seconds [60]
43
+ # +logger+:: Path to logfile or logger instance [STDOUT]
44
+ #
45
+ # Any additional options are passed to the Cache constructor
46
+ #
47
+ # Usage:
48
+ #
49
+ # # Enable caching in HTTParty, in memory, for 1 minute
50
+ # cache # Use default values
51
+ #
52
+ # # Enable caching in HTTParty, on filesystem (/tmp), for 10 minutes
53
+ # cache :store => 'file', :timeout => 600, :location => '/tmp/'
54
+ #
55
+ # # Use your own cache store (see AbstractStore class below)
56
+ # cache :store => 'memcached', :timeout => 600, :server => '192.168.1.1:1001'
57
+ #
58
+ def cache(options={})
59
+ options[:store] ||= 'memory'
60
+ options[:timeout] ||= 60
61
+ logger = options[:logger]
62
+ @cache ||= Cache.new( options.delete(:store), options )
63
+ end
64
+
65
+ end
66
+
67
+ # When included, extend class with +cache+ method
68
+ # and redefine +get+ method to use cache
69
+ #
70
+ def self.included(receiver) #:nodoc:
71
+ receiver.extend ClassMethods
72
+ receiver.class_eval do
73
+
74
+ # Get reponse from network
75
+ # TODO: Why alias :new :old is not working here? Returns NoMethodError
76
+ #
77
+ def self.get_without_caching(path, options={})
78
+ perform_request Net::HTTP::Get, path, options
79
+ end
80
+
81
+ # Get response from cache, if available
82
+ #
83
+ def self.get_with_caching(path, options={})
84
+ key = path.clone
85
+ key << options[:query].to_s if defined? options[:query]
86
+
87
+ if cache.exists?(key) and not cache.stale?(key)
88
+ Cache.logger.debug "CACHE -- GET #{path}#{options[:query]}"
89
+ return cache.get(key)
90
+ else
91
+ Cache.logger.debug "/!\\ NETWORK -- GET #{path}#{options[:query]}"
92
+ response = get_without_caching(path, options)
93
+ cache.set(key, response) if response.code == 200
94
+ return response
95
+ end
96
+ end
97
+
98
+ # Redefine original HTTParty +get+ method to use cache
99
+ #
100
+ def self.get(path, options={})
101
+ self.get_with_caching(path, options)
102
+ end
103
+
104
+ end
105
+ end
106
+
107
+ # === Cache container
108
+ #
109
+ # Pass a store name ('memory', etc) to initializer
110
+ #
111
+ class Cache
112
+ attr_accessor :store
113
+
114
+ def initialize(store, options={})
115
+ self.class.logger = options[:logger]
116
+ @store = self.class.lookup_store(store).new(options)
117
+ end
118
+
119
+ def get(key); @store.get encode(key) unless stale?(key); end
120
+ def set(key, value); @store.set encode(key), value; end
121
+ def exists?(key); @store.exists? encode(key); end
122
+ def stale?(key); @store.stale? encode(key); end
123
+
124
+ def self.logger; @logger || default_logger; end
125
+ def self.default_logger; logger = ::Logger.new(STDERR); end
126
+
127
+ # Pass a filename (String), IO object, Logger instance or +nil+ to silence the logger
128
+ def self.logger=(device); @logger = device.kind_of?(::Logger) ? device : ::Logger.new(device); end
129
+
130
+ private
131
+
132
+ # Return store class based on passed name
133
+ def self.lookup_store(name)
134
+ store_name = "#{name.capitalize}Store"
135
+ return Store::const_get(store_name)
136
+ rescue NameError => e
137
+ raise Store::StoreNotFound, "The cache store '#{store_name}' was not found. Did you loaded any such class?"
138
+ end
139
+
140
+ def encode(key); Digest::MD5.hexdigest(key); end
141
+ end
142
+
143
+
144
+ # === Cache stores
145
+ #
146
+ module Store
147
+
148
+ class StoreNotFound < StandardError; end #:nodoc:
149
+
150
+ # ==== Abstract Store
151
+ # Inherit your store from this class
152
+ # *IMPORTANT*: Do not forget to call +super+ in your +initialize+ method!
153
+ #
154
+ class AbstractStore
155
+ def initialize(options={})
156
+ raise ArgumentError, "You need to set the :timeout parameter" unless options[:timeout]
157
+ @timeout = options[:timeout]
158
+ message = "Cache: Using #{self.class.to_s.split('::').last}"
159
+ message << " in location: #{options[:location]}" if options[:location]
160
+ message << " with timeout #{options[:timeout]} sec"
161
+ Cache.logger.info message unless options[:logger].nil?
162
+ return self
163
+ end
164
+ %w{set get exists? stale?}.each do |method_name|
165
+ define_method(method_name) { raise NoMethodError, "Please implement method set in your store class" }
166
+ end
167
+ end
168
+
169
+ # ===== Store objects in memory
170
+ #
171
+ Struct.new("Response", :code, :body, :headers) { def to_s; self.body; end }
172
+ class MemoryStore < AbstractStore
173
+ def initialize(options={})
174
+ super; @store = {}; self
175
+ end
176
+ def set(key, value)
177
+ Cache.logger.info("Cache: set (#{key})")
178
+ @store[key] = [Time.now, value]; true
179
+ end
180
+ def get(key)
181
+ data = @store[key][1]
182
+ Cache.logger.info("Cache: #{data.nil? ? "miss" : "hit"} (#{key})")
183
+ data
184
+ end
185
+ def exists?(key)
186
+ !@store[key].nil?
187
+ end
188
+ def stale?(key)
189
+ return true unless exists?(key)
190
+ Time.now - created(key) > @timeout
191
+ end
192
+ private
193
+ def created(key)
194
+ @store[key][0]
195
+ end
196
+ end
197
+
198
+ # ===== Store objects on the filesystem
199
+ #
200
+ class FileStore < AbstractStore
201
+ def initialize(options={})
202
+ super
203
+ options[:location] ||= Dir::tmpdir
204
+ @path = Pathname.new( options[:location] )
205
+ FileUtils.mkdir_p( @path )
206
+ self
207
+ end
208
+ def set(key, value)
209
+ Cache.logger.info("Cache: set (#{key})")
210
+ File.open( @path.join(key), 'w' ) { |file| file << Marshal.dump(value) }
211
+ true
212
+ end
213
+ def get(key)
214
+ data = Marshal.load(File.read( @path.join(key)))
215
+ Cache.logger.info("Cache: #{data.nil? ? "miss" : "hit"} (#{key})")
216
+ data
217
+ end
218
+ def exists?(key)
219
+ File.exists?( @path.join(key) )
220
+ end
221
+ def stale?(key)
222
+ return true unless exists?(key)
223
+ Time.now - created(key) > @timeout
224
+ end
225
+ private
226
+ def created(key)
227
+ File.mtime( @path.join(key) )
228
+ end
229
+ end
230
+ end
231
+
232
+ end
233
+ end
234
+
235
+
236
+ # Major parts of this code are based on architecture of ApiCache.
237
+ # Copyright (c) 2008 Martyn Loughran
238
+ #
239
+ # Other parts are inspired by the ActiveSupport::Cache in Ruby On Rails.
240
+ # Copyright (c) 2005-2009 David Heinemeier Hansson
241
+ #
242
+ # Permission is hereby granted, free of charge, to any person obtaining
243
+ # a copy of this software and associated documentation files (the
244
+ # "Software"), to deal in the Software without restriction, including
245
+ # without limitation the rights to use, copy, modify, merge, publish,
246
+ # distribute, sublicense, and/or sell copies of the Software, and to
247
+ # permit persons to whom the Software is furnished to do so, subject to
248
+ # the following conditions:
249
+ #
250
+ # The above copyright notice and this permission notice shall be
251
+ # included in all copies or substantial portions of the Software.
252
+ #
253
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
254
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
255
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
256
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
257
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
258
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
259
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,40 @@
1
+ ### Referee.
2
+ ### file: lib/referee/player.rb
3
+
4
+ module Referee
5
+
6
+ class Player < Base
7
+
8
+ # Returns most recent shots for the specified player. Supports pagination.
9
+ def self.shots(id, options={})
10
+ get('/players/' + id.to_s + '/shots', :query => options)
11
+ end
12
+
13
+ # Returns most recent shots from the players the specified player is following. Supports pagination.
14
+ def self.shots_from_following(id, options={})
15
+ get('/players/' + id.to_s + '/shots/following', :query => options)
16
+ end
17
+
18
+ # Returns the information for the specified player.
19
+ def self.info(id)
20
+ get('/players/' + id.to_s)
21
+ end
22
+
23
+ # Returns a list of followers of the specified player.
24
+ def self.followers(id)
25
+ get('/players/' + id.to_s + '/followers')
26
+ end
27
+
28
+ # Returns a list of the players following the specified player.
29
+ def self.following(id)
30
+ get('/players/' + id.to_s + '/following')
31
+ end
32
+
33
+ # Returns a list of players the specified player drafted.
34
+ def self.draftees(id)
35
+ get('/players/' + id.to_s + '/draftees')
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,20 @@
1
+ ### Referee.
2
+ ### file: lib/referee/shot.rb
3
+
4
+ module Referee
5
+
6
+ class Shot < Base
7
+
8
+ # Returns information for the given shot.
9
+ def self.info(id)
10
+ get('/shots/' + id.to_s)
11
+ end
12
+
13
+ # Returns one of the lists (debuts, everyone, popular). Supports pagination.
14
+ def self.list(id, options={})
15
+ get('/shots/' + id.to_s, :query => options)
16
+ end
17
+
18
+ end
19
+
20
+ end
data/lib/referee.rb ADDED
@@ -0,0 +1,25 @@
1
+ ### Referee.
2
+ ### file: lib/referee.rb
3
+
4
+ require 'httparty'
5
+
6
+ directory = File.expand_path(File.dirname(__FILE__))
7
+ require File.join(directory, 'referee', 'httparty', 'icebox')
8
+
9
+ module Referee
10
+
11
+ class Base
12
+
13
+ include HTTParty
14
+ include HTTParty::Icebox
15
+
16
+ cache :store => 'memory', :timeout => 0.5, :logger => Logger.new(STDOUT)
17
+
18
+ base_uri 'api.dribbble.com'
19
+
20
+ end
21
+
22
+ end
23
+
24
+ require File.join(directory, 'referee', 'shot')
25
+ require File.join(directory, 'referee', 'player')
data/referee.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{referee}
5
+ s.version = "0.4.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ethan Turkeltaub"]
9
+ s.date = %q{2010-08-26}
10
+ s.description = %q{An easy way to communicate with the Dribbble API.}
11
+ s.email = %q{ethan.turkeltaub@gmail.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc", "lib/referee.rb", "lib/referee/httparty/icebox.rb", "lib/referee/player.rb", "lib/referee/shot.rb"]
13
+ s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.rdoc", "Rakefile", "lib/referee.rb", "lib/referee/httparty/icebox.rb", "lib/referee/player.rb", "lib/referee/shot.rb", "referee.gemspec"]
14
+ s.homepage = %q{http://github.com/eturk/referee}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Referee", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{referee}
18
+ s.rubygems_version = %q{1.3.7}
19
+ s.summary = %q{A Ruby wrapper for the Dribbble API.}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ s.add_development_dependency(%q<httparty>, [">= 0.6.1"])
27
+ else
28
+ s.add_dependency(%q<httparty>, [">= 0.6.1"])
29
+ end
30
+ else
31
+ s.add_dependency(%q<httparty>, [">= 0.6.1"])
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: referee
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
11
+ platform: ruby
12
+ authors:
13
+ - Ethan Turkeltaub
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-26 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: httparty
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 5
30
+ segments:
31
+ - 0
32
+ - 6
33
+ - 1
34
+ version: 0.6.1
35
+ type: :development
36
+ version_requirements: *id001
37
+ description: An easy way to communicate with the Dribbble API.
38
+ email: ethan.turkeltaub@gmail.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - CHANGELOG
45
+ - LICENSE
46
+ - README.rdoc
47
+ - lib/referee.rb
48
+ - lib/referee/httparty/icebox.rb
49
+ - lib/referee/player.rb
50
+ - lib/referee/shot.rb
51
+ files:
52
+ - CHANGELOG
53
+ - LICENSE
54
+ - Manifest
55
+ - README.rdoc
56
+ - Rakefile
57
+ - lib/referee.rb
58
+ - lib/referee/httparty/icebox.rb
59
+ - lib/referee/player.rb
60
+ - lib/referee/shot.rb
61
+ - referee.gemspec
62
+ has_rdoc: true
63
+ homepage: http://github.com/eturk/referee
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options:
68
+ - --line-numbers
69
+ - --inline-source
70
+ - --title
71
+ - Referee
72
+ - --main
73
+ - README.rdoc
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 11
91
+ segments:
92
+ - 1
93
+ - 2
94
+ version: "1.2"
95
+ requirements: []
96
+
97
+ rubyforge_project: referee
98
+ rubygems_version: 1.3.7
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: A Ruby wrapper for the Dribbble API.
102
+ test_files: []
103
+