rememberthemilk 0.0.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.
data/README ADDED
@@ -0,0 +1,35 @@
1
+ NAME
2
+ rememberthemilk.rb
3
+
4
+
5
+ DESCRIPTION
6
+ simple (162 loc), json only, interface to the excellent RememberTheMilk API
7
+
8
+ http://www.rememberthemilk.com/services/api/methods/
9
+
10
+ supports all methods including the complicated frob/auth get token logic
11
+
12
+
13
+ SYNOPSIS
14
+ config = {
15
+ :api_key => api_key,
16
+ :shared_secret => shared_secret,
17
+ :username => username,
18
+ :password => password
19
+ }
20
+
21
+ api = RememberTheMilk.new(config)
22
+
23
+ token = api.get_token!
24
+
25
+ config[:token] = token
26
+
27
+ api = RememberTheMilk.new(config)
28
+
29
+ jj api.ping
30
+
31
+ jj api.call('rtm.tasks.getList')
32
+
33
+ jj api.call('rtm.contacts.getList')
34
+
35
+ # etc
data/Rakefile ADDED
@@ -0,0 +1,371 @@
1
+ This.rubyforge_project = 'codeforpeople'
2
+ This.author = "Ara T. Howard"
3
+ This.email = "ara.t.howard@gmail.com"
4
+ This.homepage = "http://github.com/ahoward/#{ This.lib }/tree/master"
5
+
6
+
7
+ task :default do
8
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
9
+ end
10
+
11
+ task :test do
12
+ run_tests!
13
+ end
14
+
15
+ namespace :test do
16
+ task(:unit){ run_tests!(:unit) }
17
+ task(:functional){ run_tests!(:functional) }
18
+ task(:integration){ run_tests!(:integration) }
19
+ end
20
+
21
+ def run_tests!(which = nil)
22
+ which ||= '**'
23
+ test_dir = File.join(This.dir, "test")
24
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
25
+ test_rbs = Dir.glob(test_glob).sort
26
+
27
+ div = ('=' * 119)
28
+ line = ('-' * 119)
29
+ helper = "-r ./test/helper.rb" if test(?e, "./test/helper.rb")
30
+
31
+ test_rbs.each_with_index do |test_rb, index|
32
+ testno = index + 1
33
+ command = "#{ This.ruby } -I ./lib -I ./test/lib #{ helper } #{ test_rb }"
34
+
35
+ puts
36
+ say(div, :color => :cyan, :bold => true)
37
+ say("@#{ testno } => ", :bold => true, :method => :print)
38
+ say(command, :color => :cyan, :bold => true)
39
+ say(line, :color => :cyan, :bold => true)
40
+
41
+ system(command)
42
+
43
+ say(line, :color => :cyan, :bold => true)
44
+
45
+ status = $?.exitstatus
46
+
47
+ if status.zero?
48
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
49
+ say("SUCCESS", :color => :green, :bold => true)
50
+ else
51
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
52
+ say("FAILURE", :color => :red, :bold => true)
53
+ end
54
+ say(line, :color => :cyan, :bold => true)
55
+
56
+ exit(status) unless status.zero?
57
+ end
58
+ end
59
+
60
+
61
+ task :gemspec do
62
+ ignore_extensions = 'git', 'svn', 'tmp', /sw./, 'bak', 'gem'
63
+ ignore_directories = 'pkg'
64
+ ignore_files = 'test/log'
65
+
66
+ shiteless =
67
+ lambda do |list|
68
+ list.delete_if do |entry|
69
+ next unless test(?e, entry)
70
+ extension = File.basename(entry).split(%r/[.]/).last
71
+ ignore_extensions.any?{|ext| ext === extension}
72
+ end
73
+ list.delete_if do |entry|
74
+ next unless test(?d, entry)
75
+ dirname = File.expand_path(entry)
76
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
77
+ end
78
+ list.delete_if do |entry|
79
+ next unless test(?f, entry)
80
+ filename = File.expand_path(entry)
81
+ ignore_files.any?{|file| File.expand_path(file) == filename}
82
+ end
83
+ end
84
+
85
+ lib = This.lib
86
+ object = This.object
87
+ version = This.version
88
+ files = shiteless[Dir::glob("**/**")]
89
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
90
+ has_rdoc = true #File.exist?('doc')
91
+ test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
92
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
93
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
94
+
95
+ if This.extensions.nil?
96
+ This.extensions = []
97
+ extensions = This.extensions
98
+ %w( Makefile configure extconf.rb ).each do |ext|
99
+ extensions << ext if File.exists?(ext)
100
+ end
101
+ end
102
+ extensions = [extensions].flatten.compact
103
+
104
+ template =
105
+ if test(?e, 'gemspec.erb')
106
+ Template{ IO.read('gemspec.erb') }
107
+ else
108
+ Template {
109
+ <<-__
110
+ ## #{ lib }.gemspec
111
+ #
112
+
113
+ Gem::Specification::new do |spec|
114
+ spec.name = #{ lib.inspect }
115
+ spec.version = #{ version.inspect }
116
+ spec.platform = Gem::Platform::RUBY
117
+ spec.summary = #{ lib.inspect }
118
+ spec.description = #{ description.inspect }
119
+
120
+ spec.files = #{ files.inspect }
121
+ spec.executables = #{ executables.inspect }
122
+
123
+ spec.require_path = "lib"
124
+
125
+ spec.has_rdoc = #{ has_rdoc.inspect }
126
+ spec.test_files = #{ test_files.inspect }
127
+ #spec.add_dependency 'lib', '>= version'
128
+ spec.add_dependency 'fattr'
129
+
130
+ spec.extensions.push(*#{ extensions.inspect })
131
+
132
+ spec.rubyforge_project = #{ This.rubyforge_project.inspect }
133
+ spec.author = #{ This.author.inspect }
134
+ spec.email = #{ This.email.inspect }
135
+ spec.homepage = #{ This.homepage.inspect }
136
+ end
137
+ __
138
+ }
139
+ end
140
+
141
+ Fu.mkdir_p(This.pkgdir)
142
+ gemspec = File.join(This.pkgdir, "#{ lib }.gemspec")
143
+ open(gemspec, "w"){|fd| fd.puts(template)}
144
+ This.gemspec = gemspec
145
+ end
146
+
147
+ task :gem => [:clean, :gemspec] do
148
+ Fu.mkdir_p(This.pkgdir)
149
+ before = Dir['*.gem']
150
+ cmd = "gem build #{ This.gemspec }"
151
+ `#{ cmd }`
152
+ after = Dir['*.gem']
153
+ gem = ((after - before).first || after.first) or abort('no gem!')
154
+ Fu.mv(gem, This.pkgdir)
155
+ This.gem = File.join(This.pkgdir, File.basename(gem))
156
+ end
157
+
158
+ task :readme do
159
+ samples = ''
160
+ prompt = '~ > '
161
+ lib = This.lib
162
+ version = This.version
163
+
164
+ Dir['sample*/*'].sort.each do |sample|
165
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
166
+
167
+ cmd = "cat #{ sample }"
168
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
169
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
170
+
171
+ cmd = "ruby #{ sample }"
172
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
173
+
174
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
175
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
176
+ end
177
+
178
+ template =
179
+ if test(?e, 'readme.erb')
180
+ Template{ IO.read('readme.erb') }
181
+ else
182
+ Template {
183
+ <<-__
184
+ NAME
185
+ #{ lib }
186
+
187
+ DESCRIPTION
188
+
189
+ INSTALL
190
+ gem install #{ lib }
191
+
192
+ SAMPLES
193
+ #{ samples }
194
+ __
195
+ }
196
+ end
197
+
198
+ open("README", "w"){|fd| fd.puts template}
199
+ end
200
+
201
+
202
+ task :clean do
203
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
204
+ end
205
+
206
+
207
+ task :release => [:clean, :gemspec, :gem] do
208
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
209
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
210
+ raise "no gems?" if gems.size < 1
211
+
212
+ cmd = "gem push #{ This.gem }"
213
+ puts cmd
214
+ puts
215
+ system(cmd)
216
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
217
+
218
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
219
+ puts cmd
220
+ puts
221
+ system(cmd)
222
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
223
+ end
224
+
225
+
226
+
227
+
228
+
229
+ BEGIN {
230
+ # support for this rakefile
231
+ #
232
+ $VERBOSE = nil
233
+
234
+ require 'ostruct'
235
+ require 'erb'
236
+ require 'fileutils'
237
+ require 'rbconfig'
238
+
239
+ # fu shortcut
240
+ #
241
+ Fu = FileUtils
242
+
243
+ # cache a bunch of stuff about this rakefile/environment
244
+ #
245
+ This = OpenStruct.new
246
+
247
+ This.file = File.expand_path(__FILE__)
248
+ This.dir = File.dirname(This.file)
249
+ This.pkgdir = File.join(This.dir, 'pkg')
250
+
251
+ # grok lib
252
+ #
253
+ lib = ENV['LIB']
254
+ unless lib
255
+ lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
256
+ end
257
+ This.lib = lib
258
+
259
+ # grok version
260
+ #
261
+ version = ENV['VERSION']
262
+ unless version
263
+ require "./lib/#{ This.lib }"
264
+ This.name = lib.capitalize
265
+ This.object = eval(This.name)
266
+ version = This.object.send(:version)
267
+ end
268
+ This.version = version
269
+
270
+ # we need to know the name of the lib an it's version
271
+ #
272
+ abort('no lib') unless This.lib
273
+ abort('no version') unless This.version
274
+
275
+ # discover full path to this ruby executable
276
+ #
277
+ c = Config::CONFIG
278
+ bindir = c["bindir"] || c['BINDIR']
279
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
280
+ ruby_ext = c['EXEEXT'] || ''
281
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
282
+ This.ruby = ruby
283
+
284
+ # some utils
285
+ #
286
+ module Util
287
+ def indent(s, n = 2)
288
+ s = unindent(s)
289
+ ws = ' ' * n
290
+ s.gsub(%r/^/, ws)
291
+ end
292
+
293
+ def unindent(s)
294
+ indent = nil
295
+ s.each do |line|
296
+ next if line =~ %r/^\s*$/
297
+ indent = line[%r/^\s*/] and break
298
+ end
299
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
300
+ end
301
+ extend self
302
+ end
303
+
304
+ # template support
305
+ #
306
+ class Template
307
+ def initialize(&block)
308
+ @block = block
309
+ @template = block.call.to_s
310
+ end
311
+ def expand(b=nil)
312
+ ERB.new(Util.unindent(@template)).result(b||@block)
313
+ end
314
+ alias_method 'to_s', 'expand'
315
+ end
316
+ def Template(*args, &block) Template.new(*args, &block) end
317
+
318
+ # colored console output support
319
+ #
320
+ This.ansi = {
321
+ :clear => "\e[0m",
322
+ :reset => "\e[0m",
323
+ :erase_line => "\e[K",
324
+ :erase_char => "\e[P",
325
+ :bold => "\e[1m",
326
+ :dark => "\e[2m",
327
+ :underline => "\e[4m",
328
+ :underscore => "\e[4m",
329
+ :blink => "\e[5m",
330
+ :reverse => "\e[7m",
331
+ :concealed => "\e[8m",
332
+ :black => "\e[30m",
333
+ :red => "\e[31m",
334
+ :green => "\e[32m",
335
+ :yellow => "\e[33m",
336
+ :blue => "\e[34m",
337
+ :magenta => "\e[35m",
338
+ :cyan => "\e[36m",
339
+ :white => "\e[37m",
340
+ :on_black => "\e[40m",
341
+ :on_red => "\e[41m",
342
+ :on_green => "\e[42m",
343
+ :on_yellow => "\e[43m",
344
+ :on_blue => "\e[44m",
345
+ :on_magenta => "\e[45m",
346
+ :on_cyan => "\e[46m",
347
+ :on_white => "\e[47m"
348
+ }
349
+ def say(phrase, *args)
350
+ options = args.last.is_a?(Hash) ? args.pop : {}
351
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
352
+ keys = options.keys
353
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
354
+
355
+ color = options[:color]
356
+ bold = options.has_key?(:bold)
357
+
358
+ parts = [phrase]
359
+ parts.unshift(This.ansi[color]) if color
360
+ parts.unshift(This.ansi[:bold]) if bold
361
+ parts.push(This.ansi[:clear]) if parts.size > 1
362
+
363
+ method = options[:method] || :puts
364
+
365
+ Kernel.send(method, parts.join)
366
+ end
367
+
368
+ # always run out of the project dir
369
+ #
370
+ Dir.chdir(This.dir)
371
+ }
@@ -0,0 +1,67 @@
1
+ module RememberTheMilk
2
+ Version = '0.0.1' unless defined?(Version)
3
+ Load = Kernel.method(:load) unless defined?(Load)
4
+
5
+ def version
6
+ RememberTheMilk::Version
7
+ end
8
+
9
+ def libdir(*args, &block)
10
+ @libdir ||= File.expand_path(__FILE__).sub(/\.rb$/,'')
11
+ libdir = args.empty? ? @libdir : File.join(@libdir, *args.map{|arg| arg.to_s})
12
+ ensure
13
+ if block
14
+ begin
15
+ $LOAD_PATH.unshift(libdir)
16
+ RememberTheMilk.send(:module_eval, &block)
17
+ ensure
18
+ $LOAD_PATH.shift()
19
+ end
20
+ end
21
+ end
22
+
23
+ def load(*args, &block)
24
+ Load.call(*args, &block)
25
+ end
26
+
27
+ def new(*args, &block)
28
+ Api.new(*args, &block)
29
+ end
30
+
31
+ extend self
32
+ end
33
+
34
+ RTM = RememberTheMilk unless defined?(RTM)
35
+ Rememberthemilk = RememberTheMilk unless defined?(Rememberthemilk)
36
+
37
+ require 'md5'
38
+ require 'cgi'
39
+ require 'net/http'
40
+
41
+ begin
42
+ require 'rubygems'
43
+ rescue LoadError
44
+ nil
45
+ end
46
+
47
+ require 'json' unless defined?(JSON)
48
+ require 'options' unless defined?(Options)
49
+ require 'orderedhash' unless defined?(OrderedHash)
50
+ require 'tzinfo' unless defined?(TZInfo)
51
+
52
+
53
+ RememberTheMilk.libdir do
54
+ load 'error.rb'
55
+ load 'api.rb'
56
+ end
57
+
58
+
59
+ if __FILE__ == $0
60
+ options = YAML.load(IO.read(File.expand_path('~/.rtm.yml')))
61
+ api = RememberTheMilk::Api.new(options)
62
+ #p api.ping
63
+ #p api.call('rtm.tasks.getList')
64
+ #p api.get_token!
65
+ #p api.call('rtm.settings.getList')
66
+ #p api.localtime(utc)
67
+ end
@@ -0,0 +1,133 @@
1
+ module RememberTheMilk
2
+ class Api
3
+ Host = 'www.rememberthemilk.com' unless defined?(Host)
4
+ Url = "http://#{ Host }" unless defined?(Url)
5
+
6
+ class << Api
7
+ def url_for(*args)
8
+ options = args.options.pop
9
+
10
+ service = options[:service] || :rest
11
+ url = "/services/#{ service }"
12
+ url += args.flatten.compact.join('/') unless args.empty?
13
+ url.squeeze('/')
14
+ url.chomp!('/')
15
+ url += '/'
16
+
17
+ query = options[:query] || {}
18
+ unless query.empty?
19
+ url = url + '?' + query_string_for(query)
20
+ end
21
+
22
+ if options[:absolute]
23
+ url = Url + url
24
+ end
25
+
26
+ url
27
+ end
28
+
29
+ def query_string_for(query)
30
+ query.to_a.map{|k,v| [escape(k), escape(v)].join('=')}.join('&')
31
+ end
32
+
33
+ def escape(val)
34
+ CGI::escape(val.to_s).gsub(/ /, '+')
35
+ end
36
+ end
37
+
38
+ attr_accessor :api_key
39
+ attr_accessor :shared_secret
40
+ attr_accessor :frob
41
+ attr_accessor :token
42
+ attr_accessor :username
43
+ attr_accessor :password
44
+
45
+ def initialize(*args, &block)
46
+ options = args.options
47
+ @api_key = options[:api_key]
48
+ @shared_secret = options[:shared_secret]
49
+ @frob = options[:frob]
50
+ @token = options[:token]
51
+ @username = options[:username]
52
+ @password = options[:password]
53
+ end
54
+
55
+ def apply_for_an_api_key
56
+ url = 'http://www.rememberthemilk.com/services/api/keys.rtm'
57
+ puts(url)
58
+ open(url)
59
+ end
60
+
61
+ def api_sig_for(query)
62
+ kvs = query.to_a.map{|k,v| [k.to_s, v.to_s]}.sort
63
+ MD5.md5(@shared_secret + kvs.join).to_s
64
+ end
65
+
66
+ def ping
67
+ call('rtm.test.echo')
68
+ end
69
+
70
+ def call(method, *args, &block)
71
+ options = args.options
72
+
73
+ query = Hash.new
74
+ query['method'] = method unless method.to_s.empty?
75
+ query['api_key'] = @api_key
76
+ query['auth_token'] = @token
77
+ query['format'] = 'json'
78
+ options.each do |key, val|
79
+ query[key] = val
80
+ end
81
+ query['api_sig'] = api_sig_for(query)
82
+
83
+ url = Api.url_for(:query => query, :service => 'rest')
84
+ response = Net::HTTP.get_response(Host, url)
85
+
86
+ json = JSON.parse(response.body)
87
+
88
+ rsp = json['rsp']
89
+
90
+ if rsp['stat'] != 'ok'
91
+ raise(Error, "#{ method }(#{ args.inspect }) @ #{ url } #=> #{ rsp.inspect }")
92
+ end
93
+
94
+ rsp
95
+ end
96
+
97
+ def localtime(time)
98
+ time = Time.parse(time.to_s) unless time.is_a?(Time)
99
+ @settings ||= call('rtm.settings.getList')
100
+ @timezone = TZInfo::Timezone.get(@settings['settings']['timezone'])
101
+ @timezone.utc_to_local(time.utc)
102
+ end
103
+
104
+ # see: http://www.rememberthemilk.com/services/api/authentication.rtm
105
+ #
106
+ def get_token!
107
+ require 'mechanize'
108
+ require 'pp'
109
+ frob = get_frob
110
+ query = Hash.new
111
+ query[:frob] = frob
112
+ query[:api_key] = @api_key
113
+ query[:perms] = 'delete'
114
+ query['api_sig'] = api_sig_for(query)
115
+ url = Api.url_for(:query => query, :service => :auth, :absolute => true)
116
+ response = Net::HTTP.get_response(Host, url)
117
+ location = response.header['Location']
118
+ m = Mechanize.new
119
+ page = m.get(url)
120
+ form = page.forms.first
121
+ form['username'] = @username
122
+ form['password'] = @password
123
+ page = form.submit
124
+ rsp = call('rtm.auth.getToken', :frob => frob)
125
+ token = rsp['auth']['token']
126
+ end
127
+
128
+ def get_frob
129
+ rsp = call('rtm.auth.getFrob')
130
+ rsp['frob']
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,4 @@
1
+ module RememberTheMilk
2
+ class Error < ::StandardError
3
+ end
4
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rememberthemilk
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Ara T. Howard
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-13 00:00:00 -06:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: fattr
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description: "description: rememberthemilk kicks the ass"
34
+ email: ara.t.howard@gmail.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - lib/rememberthemilk/api.rb
43
+ - lib/rememberthemilk/error.rb
44
+ - lib/rememberthemilk.rb
45
+ - Rakefile
46
+ - README
47
+ has_rdoc: true
48
+ homepage: http://github.com/ahoward/rememberthemilk/tree/master
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ requirements: []
73
+
74
+ rubyforge_project: codeforpeople
75
+ rubygems_version: 1.3.7
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: rememberthemilk
79
+ test_files: []
80
+