referee 0.4.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.
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
+