nov-smartfm 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.
Files changed (40) hide show
  1. data/ChangeLog +43 -0
  2. data/README +45 -0
  3. data/Rakefile +155 -0
  4. data/examples/pure_ruby.rb +119 -0
  5. data/lib/ext/hash.rb +52 -0
  6. data/lib/smartfm/core/auth.rb +39 -0
  7. data/lib/smartfm/core/config.rb +51 -0
  8. data/lib/smartfm/core/version.rb +14 -0
  9. data/lib/smartfm/core.rb +3 -0
  10. data/lib/smartfm/model/base.rb +26 -0
  11. data/lib/smartfm/model/item.rb +178 -0
  12. data/lib/smartfm/model/list.rb +138 -0
  13. data/lib/smartfm/model/sentence.rb +118 -0
  14. data/lib/smartfm/model/user.rb +112 -0
  15. data/lib/smartfm/model.rb +5 -0
  16. data/lib/smartfm/rest_client/base.rb +194 -0
  17. data/lib/smartfm/rest_client/item.rb +14 -0
  18. data/lib/smartfm/rest_client/list.rb +15 -0
  19. data/lib/smartfm/rest_client/sentence.rb +12 -0
  20. data/lib/smartfm/rest_client/user.rb +14 -0
  21. data/lib/smartfm/rest_client.rb +8 -0
  22. data/lib/smartfm.rb +16 -0
  23. data/spec/ext/hash_spec.rb +11 -0
  24. data/spec/smartfm/core/auth_spec.rb +39 -0
  25. data/spec/smartfm/core/config_spec.rb +34 -0
  26. data/spec/smartfm/core/version_spec.rb +19 -0
  27. data/spec/smartfm/model/base_spec.rb +40 -0
  28. data/spec/smartfm/model/item_spec.rb +41 -0
  29. data/spec/smartfm/model/list_spec.rb +7 -0
  30. data/spec/smartfm/model/sentence_spec.rb +7 -0
  31. data/spec/smartfm/model/user_spec.rb +90 -0
  32. data/spec/smartfm/rest_client/base_spec.rb +9 -0
  33. data/spec/smartfm/rest_client/item_spec.rb +7 -0
  34. data/spec/smartfm/rest_client/list_spec.rb +7 -0
  35. data/spec/smartfm/rest_client/sentence_spec.rb +7 -0
  36. data/spec/smartfm/rest_client/user_spec.rb +7 -0
  37. data/spec/spec_helper.rb +18 -0
  38. data/test/smartfm_test.rb +8 -0
  39. data/test/test_helper.rb +3 -0
  40. metadata +132 -0
data/ChangeLog ADDED
@@ -0,0 +1,43 @@
1
+ == 0.0.1 / 2008-10-13
2
+
3
+ * initial release
4
+
5
+ == 0.0.2
6
+
7
+ == 0.0.3
8
+
9
+ == 0.0.4
10
+
11
+ * add new API calls
12
+ * add new attributes
13
+
14
+ == 0.1.0
15
+
16
+ * add Smartfm::Auth (supports basic_auth and oauth)
17
+ * add List#create, List#delete, List#add_item, List#delete_item
18
+
19
+ == 0.1.1
20
+
21
+ * remove Mechanize
22
+
23
+ == 0.2.0
24
+
25
+ * support almost all API calls
26
+
27
+ == 0.2.1
28
+
29
+ * maintenance release
30
+
31
+ == 0.2.2
32
+
33
+ * add attribution support for add_image & add_sound APIs
34
+
35
+ == 0.3.0
36
+
37
+ * iKnow! => smart.fm
38
+ * now, iKnow! is the name of Flash study application
39
+
40
+ == 0.3.1
41
+
42
+ * add sessions API support
43
+ * fixed extract API bugs
data/README ADDED
@@ -0,0 +1,45 @@
1
+ = smart.fm
2
+
3
+ by nov <nov@cerego.com>
4
+
5
+ == Description
6
+
7
+ This rubygem is a wrapper of smart.fm API.
8
+ You can get pure-ruby example at examples/pure_ruby.rb.
9
+ http://github.com/nov/smartfm/tree/master/examples/pure_ruby.rb
10
+
11
+ It shows all API calls you can use with this gem.
12
+
13
+ == Installation
14
+
15
+ git clone http://github.com/nov/smartfm.git
16
+ cd smartfm
17
+ rake install
18
+
19
+ === Archive Installation
20
+
21
+ rake install
22
+
23
+ === Gem Installation
24
+
25
+ gem install smartfm
26
+
27
+ == Features/Problems
28
+
29
+ Test! Test!! Test!!!
30
+
31
+ Create/Add/Delete APIs are not implemented.
32
+ They will be implemented in a few weeks.
33
+
34
+ smart.fm OAuth is still pre-alpha.
35
+
36
+ == Synopsis
37
+
38
+ See examples and smart.fm Developers, please.
39
+ smart.fm Developers (http://developer.smart.fm)
40
+
41
+ == Copyright
42
+
43
+ Author:: nov <nov@cerego.com>
44
+ Copyright:: Copyright (c) 2009 nov
45
+ License:: MIT License
data/Rakefile ADDED
@@ -0,0 +1,155 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'rake/contrib/sshpublisher'
10
+ require 'fileutils'
11
+ include FileUtils
12
+
13
+ NAME = "smartfm"
14
+ AUTHOR = "nov"
15
+ EMAIL = "developer@smart.fm"
16
+ DESCRIPTION = "A rubygem for smart.fm APIs"
17
+ RUBYFORGE_PROJECT = NAME
18
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
19
+ BIN_FILES = %w( )
20
+
21
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib"
22
+ require 'lib/smartfm'
23
+ VERS = Smartfm::Version.to_version
24
+ REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
25
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config']
26
+ RDOC_OPTS = [
27
+ '--title', "#{NAME} documentation",
28
+ "--charset", "utf-8",
29
+ "--opname", "index.html",
30
+ "--line-numbers",
31
+ "--main", "README",
32
+ "--inline-source",
33
+ ]
34
+
35
+ task :default => [:test]
36
+ task :package => [:clean]
37
+
38
+ Rake::TestTask.new("test") do |t|
39
+ t.libs << "test"
40
+ t.pattern = "test/**/*_test.rb"
41
+ t.verbose = true
42
+ end
43
+
44
+ Rake::TestTask.new("spec") do |t|
45
+ t.libs << "spec"
46
+ t.pattern = "spec/**/*_spec.rb"
47
+ t.verbose = true
48
+ end
49
+
50
+ spec = Gem::Specification.new do |s|
51
+ s.name = NAME
52
+ s.version = VERS
53
+ s.platform = Gem::Platform::RUBY
54
+ s.has_rdoc = true
55
+ s.extra_rdoc_files = ["README", "ChangeLog"]
56
+ s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
57
+ s.summary = DESCRIPTION
58
+ s.description = DESCRIPTION
59
+ s.author = AUTHOR
60
+ s.email = EMAIL
61
+ s.homepage = HOMEPATH
62
+ s.executables = BIN_FILES
63
+ s.rubyforge_project = RUBYFORGE_PROJECT
64
+ s.bindir = "bin"
65
+ s.require_path = "lib"
66
+ #s.autorequire = ""
67
+ s.test_files = Dir["test/*_test.rb"]
68
+
69
+ s.add_dependency('json')
70
+ s.add_dependency('oauth')
71
+ # s.required_ruby_version = '>= 1.8.6'
72
+
73
+ s.files = %w(README ChangeLog Rakefile) +
74
+ Dir.glob("{bin,doc,test,spec,lib,templates,extras,website,script}/**/*") +
75
+ Dir.glob("ext/**/*.{h,c,rb}") +
76
+ Dir.glob("examples/**/*.rb") +
77
+ Dir.glob("tools/*.rb") +
78
+ Dir.glob("rails/*.rb")
79
+
80
+ s.extensions = FileList["ext/**/extconf.rb"].to_a
81
+ end
82
+
83
+ Rake::GemPackageTask.new(spec) do |p|
84
+ p.need_tar = true
85
+ p.gem_spec = spec
86
+ end
87
+
88
+ desc "Install"
89
+ task :install do
90
+ name = "#{NAME}-#{VERS}.gem"
91
+ sh %{rake package}
92
+ sh %{sudo gem install pkg/#{name}}
93
+ end
94
+
95
+ desc "Uninstall"
96
+ task :uninstall => [:clean] do
97
+ sh %{sudo gem uninstall #{NAME}}
98
+ end
99
+
100
+
101
+ Rake::RDocTask.new do |rdoc|
102
+ rdoc.rdoc_dir = 'html'
103
+ rdoc.options += RDOC_OPTS
104
+ rdoc.template = "resh"
105
+ #rdoc.template = "#{ENV['template']}.rb" if ENV['template']
106
+ if ENV['DOC_FILES']
107
+ rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
108
+ else
109
+ rdoc.rdoc_files.include('README', 'ChangeLog')
110
+ rdoc.rdoc_files.include('lib/**/*.rb')
111
+ rdoc.rdoc_files.include('ext/**/*.c')
112
+ end
113
+ end
114
+
115
+ desc "Publish to RubyForge"
116
+ task :rubyforge => [:rdoc, :package] do
117
+ require 'rubyforge'
118
+ Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, 'nov').upload
119
+ end
120
+
121
+ # rake release VERSION=x.y.z
122
+ desc 'Package and upload the release to rubyforge.'
123
+ task :release => [:clean, :package] do |t|
124
+ v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
125
+ abort "Versions don't match #{v} vs #{VERS}" unless v == VERS
126
+ pkg = "pkg/#{NAME}-#{VERS}"
127
+
128
+ require 'rubyforge'
129
+ rf = RubyForge.new.configure
130
+ puts "Logging in"
131
+ rf.login
132
+
133
+ c = rf.userconfig
134
+ # c["release_notes"] = description if description
135
+ # c["release_changes"] = changes if changes
136
+ c["preformatted"] = true
137
+
138
+ files = [
139
+ "#{pkg}.tgz",
140
+ "#{pkg}.gem"
141
+ ].compact
142
+
143
+ puts "Releasing #{NAME} v. #{VERS}"
144
+ rf.add_release RUBYFORGE_PROJECT, NAME, VERS, *files
145
+ end
146
+
147
+ desc 'Show information about the gem.'
148
+ task :debug_gem do
149
+ puts spec.to_ruby
150
+ end
151
+
152
+ desc 'Update gem spec'
153
+ task :gemspec do
154
+ open("#{NAME}.gemspec", 'w').write spec.to_ruby
155
+ end
@@ -0,0 +1,119 @@
1
+ require 'rubygems'
2
+ require 'smartfm'
3
+ require 'oauth/consumer'
4
+
5
+ Smartfm::Config.init do |conf|
6
+ conf.api_host = 'api.smart.fm'
7
+ conf.api_key = '' # 'SET_YOUR_API_KEY'
8
+ conf.oauth_consumer_key = '' # 'SET_YOUR_OAUTH_CONSUMER_KEY'
9
+ conf.oauth_consumer_secret = '' # 'SET_YOUR_OAUTH_CONSUMER_SECRET'
10
+ conf.oauth_http_method = :post
11
+ conf.oauth_scheme = :header
12
+ conf.timeout = 15
13
+ end
14
+
15
+ # Edit here
16
+ OAUTH_ACCESS_TOKEN = ''
17
+ OAUTH_ACCESS_TOKEN_SECRET = ''
18
+
19
+ # Edit here
20
+ SMARTFM_USERNAME = ''
21
+ SMARTFM_PASSWORD = ''
22
+
23
+ please_get_api_key =<<EOS
24
+ This example needs your own smart.fm API key.
25
+ (for only Smartfm::Item.extract example)
26
+
27
+ You can get smart.fm API key at smart.fm Developers.
28
+ smart.fm Developers (http://developer.smart.fm/)
29
+
30
+ Thanks!
31
+ EOS
32
+
33
+ if Smartfm::Config.api_key == ''
34
+ raise ArgumentError.new(please_get_api_key)
35
+ end
36
+
37
+
38
+ ###########################
39
+ ## WITHOUT AUTHORIZATION ##
40
+ ###########################
41
+
42
+ puts "WITHOUT AUTHORIZATION"
43
+
44
+ ## User API
45
+ puts "# User API Calls"
46
+ @user = Smartfm::User.find('kirk')
47
+ @user.items(:include_sentences => true)
48
+ @user.lists
49
+ @user.friends
50
+ @user.study.results
51
+ @user.study.total_summary
52
+ @matched_users = Smartfm::User.matching('matake')
53
+
54
+ ## List API
55
+ puts "# List API Calls"
56
+ @recent_lists = Smartfm::List.recent
57
+ @list = Smartfm::List.find(31509, :include_sentences => true, :include_items => true)
58
+ @list.items
59
+ @list.sentences
60
+ @matched_lists = Smartfm::List.matching("イタリア語であいさつ")
61
+
62
+ ## Item API
63
+ puts "# Item API Calls"
64
+ @recent_items = Smartfm::Item.recent(:include_sentences => true)
65
+ @item = Smartfm::Item.find(437525)
66
+ @matched_items = Smartfm::Item.matching('record', :include_sentences => true)
67
+ @items_hash = Smartfm::Item.extract("sometimes, often, electrical")
68
+ @items = Smartfm::Item.extract("sometimes, often, electrical", :words_only => false)
69
+ @items.first.sentences
70
+
71
+ ## Sentence API
72
+ puts "# Sentence API Calls"
73
+ @recent_sentences = Smartfm::Sentence.recent
74
+ @sentence = Smartfm::Sentence.find(312271)
75
+ @matched_sentences = Smartfm::Sentence.matching('record')
76
+
77
+
78
+ ########################
79
+ ## WITH AUTHORIZATION ##
80
+ ########################
81
+
82
+ auth = case
83
+ when !OAUTH_ACCESS_TOKEN.empty?
84
+ if Smartfm::Config.oauth_consumer_key.empty? or Smartfm::Config.oauth_consumer_secret.empty?
85
+ raise ArgumentError.new("oauth_consumer_key and oauth_consumer_secret are required")
86
+ end
87
+ Smartfm::Auth.new(:token => OAUTH_ACCESS_TOKEN, :secret => OAUTH_ACCESS_TOKEN_SECRET)
88
+ when SMARTFM_USERNAME != ''
89
+ Smartfm::Auth.new(:username => SMARTFM_USERNAME, :password => SMARTFM_PASSWORD)
90
+ else
91
+ nil
92
+ end
93
+ unless auth
94
+ puts "Skip calls which require authentication"
95
+ exit
96
+ else
97
+ puts "## WITH AUTHORIZATION :: #{auth.mode}"
98
+ end
99
+
100
+ ## List API
101
+ puts "# List API"
102
+ @list = Smartfm::List.create(auth, :title => 'smart.fm gem test', :description => 'A list for smart.fm gem test')
103
+ @list.add_item(auth, Smartfm::Item.find(437525))
104
+ @list.delete_item(auth, @list.items.first)
105
+ @list.delete(auth)
106
+
107
+ ## Item API
108
+ puts "# Item API"
109
+ @item = Smartfm::Item.create(auth, :cue => {:text => 'hello world! 2', :language => 'en', :part_of_speech => 'E'},
110
+ :response => {:text => 'ハローワールド!', :language => 'ja'})
111
+ @item.add_image(auth, 'http://farm4.static.flickr.com/3276/3102381796_a33c1ffdf1.jpg')
112
+ @item.add_sound(auth, 'http://matake.jp/download/hello_world.mp3')
113
+ @item.add_tags(auth, 'sample', 'programming')
114
+
115
+ ## Sentence API
116
+ puts "# Sentence API"
117
+ @sentence = Smartfm::Sentence.create(auth, :text => 'Hello World!', :item => Smartfm::Item.matching('hello world').first)
118
+ @sentence.add_image(auth, 'http://farm4.static.flickr.com/3276/3102381796_a33c1ffdf1.jpg')
119
+ @sentence.add_sound(auth, 'http://matake.jp/download/hello_world.mp3')
data/lib/ext/hash.rb ADDED
@@ -0,0 +1,52 @@
1
+ class Hash
2
+
3
+ def to_http_str
4
+ result = ''
5
+ return result if self.empty?
6
+ self.each do |key, val|
7
+ result << "#{key}=#{URI.encode(val.to_s)}&"
8
+ end
9
+ result.chop
10
+ end
11
+
12
+ def symbolize_keys!
13
+ self.each do |key, value|
14
+ unless self.delete(key.to_s).nil?
15
+ if value.is_a?(Hash)
16
+ value.symbolize_keys!
17
+ elsif value.is_a?(Array)
18
+ value.map!{ |v| v.symbolize_keys! if v.is_a?(Hash) }
19
+ end
20
+ self[key.to_sym] = value
21
+ end
22
+ end
23
+ self
24
+ end
25
+
26
+ def stringfy_keys!
27
+ self.each do |key, value|
28
+ unless self.delete(key.to_sym).nil?
29
+ if value.is_a?(Hash)
30
+ value.stringfy_keys!
31
+ elsif value.is_a?(Array)
32
+ value.map!{ |v| v.stringfy_keys! if v.is_a?(Hash) }
33
+ end
34
+ self[key.to_s] = value
35
+ end
36
+ end
37
+ self
38
+ end
39
+
40
+ def stringfy_values!
41
+ self.each do |key, value|
42
+ if value.is_a?(Hash)
43
+ value.stringfy_values!
44
+ elsif value.is_a?(Array)
45
+ value.map!{ |v| v.stringfy_values! if v.is_a?(Hash) }
46
+ end
47
+ self[key] = value.to_s
48
+ end
49
+ self
50
+ end
51
+
52
+ end
@@ -0,0 +1,39 @@
1
+ require 'oauth/consumer'
2
+
3
+ class Smartfm::Auth
4
+ attr_accessor :mode, :auth_token
5
+
6
+ class Basic
7
+ attr_reader :username, :password
8
+
9
+ def initialize(username, password)
10
+ @username = username
11
+ @password = password
12
+ end
13
+ end
14
+
15
+ def initialize(options = {})
16
+ if options[:username] && options[:password]
17
+ @mode = :basic_auth
18
+ @auth_token = Basic.new(options[:username], options[:password])
19
+ elsif options[:token] && options[:secret]
20
+ @mode = :oauth
21
+ @auth_token = OAuth::AccessToken.new(Smartfm::Auth.consumer, options[:token], options[:secret])
22
+ else
23
+ raise ArgumentError.new('{:auth => "oauth_access_token", :secret => "oauth_access_token_secret"} or {:username "smartfm_username", :password => "smartfm_password"} is needed')
24
+ end
25
+ end
26
+
27
+ def self.consumer
28
+ @@consumer ||= OAuth::Consumer.new(
29
+ Smartfm::Config.oauth_consumer_key,
30
+ Smartfm::Config.oauth_consumer_secret,
31
+ :http_method => Smartfm::Config.oauth_http_method,
32
+ :scheme => Smartfm::Config.oauth_scheme,
33
+ :site => Smartfm::Config.api_base_url,
34
+ :authorize_url => "#{Smartfm::Config.base_url}/oauth/authorize"
35
+ )
36
+ end
37
+
38
+ alias_method :account, :auth_token
39
+ end
@@ -0,0 +1,51 @@
1
+ require 'singleton'
2
+
3
+ class Smartfm::Config
4
+ include Singleton
5
+ ATTRIBUTES = [ :protocol, :host, :port, :api_protocol, :api_host, :api_port, :api_key, :timeout,
6
+ :oauth_consumer_key, :oauth_consumer_secret, :oauth_http_method, :oauth_scheme,
7
+ :user_agent, :application_name, :application_version, :application_url ]
8
+ attr_accessor *ATTRIBUTES
9
+
10
+ def self.init(&block)
11
+ conf = Smartfm::Config.instance
12
+ { :protocol => 'http',
13
+ :host => 'smart.fm',
14
+ :port => 80,
15
+ :api_protocol => 'http',
16
+ :api_host => 'api.smart.fm',
17
+ :api_port => 80,
18
+ :api_key => '',
19
+ :timeout => 30,
20
+ :oauth_consumer_key => '',
21
+ :oauth_consumer_secret => '',
22
+ :oauth_http_method => :post,
23
+ :oauth_scheme => :header,
24
+ :user_agent => 'default',
25
+ :application_name => 'smart.fm gem',
26
+ :application_version => Smartfm::Version.to_version,
27
+ :application_url => 'http://github.com/nov/smartfm'
28
+ }.each do |key, value| conf.send("#{key}=", value) end
29
+ yield conf if block_given?
30
+ conf
31
+ end
32
+
33
+ def base_url
34
+ port = self.port==80 ? nil : ":#{self.port}"
35
+ "#{self.protocol}://#{self.host}#{port}"
36
+ end
37
+
38
+ def api_base_url
39
+ port = self.api_port==80 ? nil : ":#{self.api_port}"
40
+ "#{self.api_protocol}://#{self.api_host}#{port}"
41
+ end
42
+
43
+ # hack: Object.timeout is already defined..
44
+ def self.timeout
45
+ instance.timeout
46
+ end
47
+
48
+ def self.method_missing(method, *args)
49
+ Smartfm::Config.instance.send(method, *args)
50
+ end
51
+ end
@@ -0,0 +1,14 @@
1
+ module Smartfm::Version
2
+ MAJOR = 0
3
+ MINOR = 4
4
+ REVISION = 0
5
+ class << self
6
+ def to_version
7
+ "#{MAJOR}.#{MINOR}.#{REVISION}"
8
+ end
9
+
10
+ def to_name
11
+ "#{MAJOR}_#{MINOR}_#{REVISION}"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ require 'smartfm/core/version'
2
+ require 'smartfm/core/config'
3
+ require 'smartfm/core/auth'
@@ -0,0 +1,26 @@
1
+ class Smartfm::Base
2
+
3
+ def self.attributes; self::ATTRIBUTES end
4
+
5
+ def attributes; self.class.attributes end
6
+
7
+ def self.deserialize(hash, params = {})
8
+ return nil if hash.nil?
9
+
10
+ klass = params[:as] ? params[:as] : self
11
+ if hash.is_a?(Array)
12
+ hash.inject([]) { |results, hash|
13
+ hash.symbolize_keys!
14
+ results << klass.new(hash)
15
+ }
16
+ else
17
+ hash.symbolize_keys!
18
+ klass.new(hash)
19
+ end
20
+ end
21
+
22
+ def deserialize(hash, params = {})
23
+ self.class.deserialize(hash, params)
24
+ end
25
+
26
+ end