nowa-top4r 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,5 @@
1
+ === 0.0.1 / 2009-06-22
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Nowa Zhu <nowazhu@gmail.com>, http://nowa.me.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,20 @@
1
+ = TOP4R
2
+
3
+ * http://top4r.labs.nowa.me
4
+ * Thanks Twitter4R <http://twitter4r.rubyforge.org>.
5
+
6
+ == DESCRIPTION:
7
+
8
+ TOP4R封装了淘宝开发平台的接口,帮助你快速构建基于TOP的应用程序。
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ * 待续...
13
+
14
+ == REQUIREMENTS:
15
+
16
+ * rubygems
17
+
18
+ == INSTALL:
19
+
20
+ sudo gem install nowa-top4r -s http://gems.github.com
data/TODO ADDED
File without changes
data/bin/top4rsh ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+
@@ -0,0 +1,135 @@
1
+ class Top4R::Client
2
+ alias :old_inspect :inspect
3
+ attr_accessor :total_results
4
+ attr_reader :login
5
+
6
+ def inspect
7
+ s = old_inspect
8
+ s.gsub!(/@app_secret=".*?"/, '@app_secret="XXXX"')
9
+ end
10
+
11
+ def init
12
+ total_results = 0
13
+ if @parameters and @session
14
+ @parameters = Base64.decode64(@parameters).split('&').inject({}) do |hsh, i| kv = i.split('='); hsh[kv[0]] = kv[1]; hsh end
15
+ @login = user(@parameters['visitor_nick'])
16
+ # puts "login: #{@login.inspect}"
17
+ end
18
+ end
19
+
20
+ protected
21
+ attr_accessor :app_key, :app_secret, :parameters, :session
22
+
23
+ def login_required(model, method)
24
+ return if logged_in?
25
+ raise Top4R::LoginRequiredError.new({:model => model, :method => method})
26
+ end
27
+
28
+ def http_connect(body=nil, &block)
29
+ require_block(block_given?)
30
+ connection = create_http_connection
31
+ connection.start do |connection|
32
+ request = yield connection if block_given?
33
+ # puts "conn: #{connection.inspect}"
34
+ # puts "request: #{request.inspect}"
35
+ response = connection.request(request, body)
36
+ puts "response: #{response.body}"
37
+ handle_rest_response(response)
38
+ response
39
+ end
40
+ end
41
+
42
+ # "Blesses" model object with client information
43
+ def bless_model(model)
44
+ model.bless(self) if model
45
+ end
46
+
47
+ def bless_models(list)
48
+ return bless_model(list) if list.respond_to?(:client=)
49
+ list.collect { |model| bless_model(model) } if list.respond_to?(:collect)
50
+ end
51
+
52
+ private
53
+ @@http_header = nil
54
+
55
+ def valid_method(method, methods, model, force_login = false)
56
+ login_required(model, method) if (@@no_login_required_methods[model].is_a?(Hash) and !@@no_login_required_methods[model].keys.member?(method)) or force_login
57
+ raise ArgumentError, "Invalid #{model} method: #{method}" unless methods.keys.member?(method)
58
+ end
59
+
60
+ def raise_rest_error(response, uri = nil)
61
+ map = JSON.parse(response.body)
62
+ raise Top4R::RESTError.new(:code => response.code,
63
+ :message => response.message,
64
+ :error => map["error_rsp"],
65
+ :uri => uri)
66
+ end
67
+
68
+ def handle_rest_response(response, uri = nil)
69
+ unless response.is_a?(Net::HTTPSuccess)
70
+ raise_rest_error(response, uri)
71
+ end
72
+
73
+ map = JSON.parse(response.body)
74
+ raise Top4R::RESTError.new(:code => map["error_rsp"]["code"],
75
+ :message => map["error_rsp"]["msg"],
76
+ :error => map["error_rsp"],
77
+ :uri => uri) if map["error_rsp"].is_a?(Hash)
78
+ end
79
+
80
+ def create_http_connection
81
+ protocol, host, port = (@@config.env == :production ? @@config.protocol : @@config.test_protocol), (@@config.env == :production ? @@config.host : @@config.test_host), (@@config.env == :production ? @@config.port : @@config.test_port)
82
+ conn = Net::HTTP.new(host, port,
83
+ @@config.proxy_host, @@config.proxy_port,
84
+ @@config.proxy_user, @@config.proxy_pass)
85
+ if protocol == :ssl
86
+ conn.use_ssl = true
87
+ conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
88
+ end
89
+ conn
90
+ end
91
+
92
+ def http_header
93
+ # can cache this in class variable since all "variables" used to
94
+ # create the contents of the HTTP header are determined by other
95
+ # class variables that are not designed to change after instantiation.
96
+ @@http_header ||= {
97
+ 'User-Agent' => "Top4R v#{Top4R::Version.to_version} [#{@@config.user_agent}]",
98
+ 'Accept' => 'text/x-json',
99
+ 'X-TOP-Client' => @@config.application_name,
100
+ 'X-TOP-Client-Version' => @@config.application_version,
101
+ 'X-TOP-Client-URL' => @@config.application_url,
102
+ }
103
+ @@http_header
104
+ end
105
+
106
+ def append_top_params(params)
107
+ params = params.merge({
108
+ :session => @session,
109
+ :timestamp => Time.now.strftime("%Y-%m-%d %H:%M:%S"),
110
+ :format => "#{@@config.format}",
111
+ :app_key => @app_key,
112
+ :v => "1.0"
113
+ })
114
+ params = params.merge({
115
+ :sign => Digest::MD5.hexdigest(params.sort {|a,b| "#{a[0]}"<=>"#{b[0]}"}.flatten.unshift(@app_secret).join).upcase
116
+ })
117
+ end
118
+
119
+ def create_http_get_request(method, params = {})
120
+ uri = @@config.env == :production ? @@config.rest_uri : @@config.test_rest_uri
121
+ params = append_top_params(params.merge({:method => method}))
122
+ path = (params.size > 0) ? "#{uri}?#{params.to_http_str}" : uri
123
+ puts "path: #{path}"
124
+ Net::HTTP::Get.new(path, http_header)
125
+ end
126
+
127
+ def create_http_post_request(uri)
128
+ Net::HTTP::Post.new(uri, http_header)
129
+ end
130
+
131
+ def create_http_delete_request(uri, params = {})
132
+ path = (params.size > 0) ? "#{uri}?#{params.to_http_str}" : uri
133
+ Net::HTTP::Delete.new(path, http_header)
134
+ end
135
+ end
@@ -0,0 +1,45 @@
1
+ class Top4R::Client
2
+ @@AREA_METHODS = {
3
+ :list => 'taobao.areas.get'
4
+ }
5
+
6
+ @@LOGISTIC_COMPANY_METHODS = {
7
+ :list => 'taobao.logisticcompanies.get'
8
+ }
9
+
10
+ @@DELIVERY_METHODS = {
11
+ :send => 'taobao.delivery.send'
12
+ }
13
+
14
+ def areas(method = :list, options = {}, &block)
15
+ valid_method(method, @@AREA_METHODS, :area)
16
+ params = {:fields => Top4R::Area.fields}.merge(options)
17
+ response = http_connect {|conn| create_http_get_request(@@AREA_METHODS[method], params)}
18
+ areas = Top4R::Area.unmarshal(JSON.parse(response.body)["rsp"]["areas"])
19
+ areas.each {|area| bless_model(area); yield area if block_given?}
20
+ areas
21
+ end
22
+
23
+ def logistic_companies(method = :list, options = {}, &block)
24
+ valid_method(method, @@LOGISTIC_COMPANY_METHODS, :logistic_company)
25
+ params = {:fields => Top4R::LogisticCompany.fields}.merge(options)
26
+ response = http_connect {|conn| create_http_get_request(@@LOGISTIC_COMPANY_METHODS[method], params)}
27
+ logistic_companies = Top4R::LogisticCompany.unmarshal(JSON.parse(response.body)["rsp"]["logistic_companies"])
28
+ logistic_companies.each {|logistic_company| bless_model(logistic_company); yield logistic_company if block_given?}
29
+ logistic_companies
30
+ end
31
+
32
+ def deliver_trade(t, method = :send, options = {})
33
+ valid_method(method, @@DELIVERY_METHODS, :delivery)
34
+ params = {}
35
+ if t.is_a?(Top4R::Delivery)
36
+ params = t.to_hash
37
+ else
38
+ t = t.tid if t.is_a?(Top4R::Trade)
39
+ params = options.merge(:tid => t)
40
+ end
41
+ response = http_connect {|conn| create_http_get_request(@@DELIVERY_METHODS[method], params)}
42
+ json = JSON.parse(response.body)
43
+ json.is_a?(Hash) ? json["rsp"]["is_success"] : false
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ class Top4R::Client
2
+ @@SUITE_METHODS = {
3
+ :list => 'taobao.suites.get',
4
+ }
5
+
6
+ def suites(u, service_code, method = :list, options = {}, &block)
7
+ valid_method(method, @@SUITE_METHODS, :suite)
8
+ u = u.nick if u.is_a?(Top4R::User)
9
+ params = {:service_code => service_code}.merge(options).merge(:nick => u)
10
+ response = http_connect {|conn| create_http_get_request(@@SUITE_METHODS[method], params)}
11
+ suites = Top4R::Suite.unmarshal(JSON.parse(response.body)["rsp"]["suite"])
12
+ suites.each {|suite| bless_model(suite); yield suite if block_given?}
13
+ # puts "\nsuites: #{suites.inspect}"
14
+ @total_results = JSON.parse(response.body)["rsp"]["totalResults"].to_i
15
+ suites
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ class Top4R::Client
2
+ @@TRADE_METHODS = {
3
+ :bought_list => 'taobao.trades.bought.get',
4
+ :sold_list => 'taobao.trades.sold.get',
5
+ :increments_list => 'taobao.trades.sold.increment.get',
6
+ :info => 'taobao.trade.get',
7
+ :fullinfo => 'taobao.trade.fullinfo.get',
8
+ :close => 'taobao.trade.close',
9
+ :add_memo => 'taobao.trade.memo.add',
10
+ :update_memo => 'taobao.trade.memo.update',
11
+ :confirmfee => 'taobao.trade.confirmfee.get'
12
+ }
13
+
14
+ def trades_for(method = :bought_list, options = {}, &block)
15
+ valid_method(method, @@TRADE_METHODS, :trade)
16
+ params = {:fields => Top4R::Trade.fields}.merge(options)
17
+ if method == :increments_list
18
+ now = Time.now
19
+ params = {:start_modified => (now - 24.hours).strftime("%Y-%m-%d %H:%M:%S"), :end_modified => now.strftime("%Y-%m-%d %H:%M:%S")}.merge(params)
20
+ end
21
+ response = http_connect {|conn| create_http_get_request(@@TRADE_METHODS[method], params)}
22
+ trades = Top4R::Trade.unmarshal(JSON.parse(response.body)["rsp"]["trades"])
23
+ trades.each {|trade| bless_model(trade); yield trade if block_given?}
24
+ # puts "\ntrades: #{trades.inspect}"
25
+ @total_results = JSON.parse(response.body)["rsp"]["totalResults"].to_i
26
+ trades
27
+ end
28
+
29
+ def trade(t, method = :info, options = {})
30
+ valid_method(method, @@TRADE_METHODS, :trade)
31
+ t = t.tid if t.is_a?(Top4R::Trade)
32
+ params = {:fields => Top4R::Trade.fields}.merge(options).merge(:tid => t)
33
+ response = http_connect {|conn| create_http_get_request(@@TRADE_METHODS[method], params)}
34
+ parsed_body = JSON.parse(response.body)
35
+
36
+ if [:info, :fullinfo].member?(method)
37
+ trades = Top4R::Trade.unmarshal(parsed_body["rsp"]["trades"])
38
+ bless_model(trades.first)
39
+ elsif method == :confirmfee
40
+ confirmfees = Top4R::TradeConfirmFee.unmarshal(parsed_body["rsp"]["confirmFees"])
41
+ bless_models(confirmfees)
42
+ elsif [:close, :update_memo].member?(method)
43
+ parsed_body["rsp"]["modified"]
44
+ elsif method == :add_memo
45
+ parsed_body["rsp"]["created"]
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,31 @@
1
+ class Top4R::Client
2
+ @@USER_METHODS = {
3
+ :info => 'taobao.user.get',
4
+ :multi_info => 'taobao.users.get'
5
+ }
6
+
7
+ def logged_in?
8
+ @login.is_a?(Top4R::User) ? true : false
9
+ end
10
+
11
+ def user(u, method = :info, options = {})
12
+ valid_method(method, @@USER_METHODS, :user)
13
+ u = u.nick if u.is_a?(Top4R::User)
14
+ users = user_request(u, method, options)
15
+ method == :info ? bless_model(users.first) : bless_models(users)
16
+ end
17
+
18
+ def my(method, options = {})
19
+ valid_method(method, @@USER_METHODS, :user, true)
20
+ users = user_request(@login.nick, method, options)
21
+ method == :info ? bless_model(users.first) : bless_models(users)
22
+ end
23
+
24
+ protected
25
+
26
+ def user_request(u, method, options)
27
+ params = {:fields => Top4R::User.fields}.merge(options).merge(:nick => u)
28
+ response = http_connect {|conn| create_http_get_request(@@USER_METHODS[method], params)}
29
+ Top4R::User.unmarshal(JSON.parse(response.body)["rsp"]["users"])
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ class Top4R::Client
2
+ include Top4R::ClassUtilMixin
3
+
4
+ @@no_login_required_methods = {
5
+ :user => {
6
+ :info => 'taobao.user.get',
7
+ :multi_info => 'taobao.users.get'
8
+ },
9
+ :trade => {},
10
+ :area => {
11
+ :list => 'taobao.areas.get'
12
+ },
13
+ :logistic_company => {
14
+ :list => 'taobao.logisticcompanies.get'
15
+ }
16
+ }
17
+ end
18
+
19
+ require 'top4r/client/base'
20
+ require 'top4r/client/user'
21
+ require 'top4r/client/shipping'
22
+ require 'top4r/client/trade'
23
+ require 'top4r/client/suite'
@@ -0,0 +1,74 @@
1
+ module Top4R
2
+ # A rails like config object
3
+ class Config
4
+ include ClassUtilMixin
5
+ @@ATTRIBUTES = [
6
+ :env,
7
+ :host,
8
+ :rest_uri,
9
+ :port,
10
+ :protocol,
11
+ :test_host,
12
+ :test_rest_uri,
13
+ :test_port,
14
+ :test_protocol,
15
+ :proxy_host,
16
+ :proxy_port,
17
+ :proxy_user,
18
+ :proxy_pass,
19
+ :format,
20
+ :application_name,
21
+ :application_key,
22
+ :application_secret,
23
+ :application_version,
24
+ :application_url,
25
+ :user_agent,
26
+ :source
27
+ ]
28
+ attr_accessor *@@ATTRIBUTES
29
+
30
+ # Override of Object#eql? to ensure RSpec specifications run
31
+ # correctly. Also done to follow Ruby best practices.
32
+ def eql?(other)
33
+ return true if self == other
34
+ @@ATTRIBUTES.each do |att|
35
+ return false unless self.send(att).eql?(other.send(att))
36
+ end
37
+ true
38
+ end
39
+ end # Config class
40
+
41
+ class Client
42
+ @@defaults = {
43
+ :env => :test,
44
+ :host => 'gw.api.taobao.com',
45
+ :rest_uri => '/router/rest',
46
+ :port => 80,
47
+ :protocol => :http,
48
+ :test_host => 'gw.sandbox.taobao.com',
49
+ :test_rest_uri => '/router/rest',
50
+ :test_port => 80,
51
+ :test_protocol => :http,
52
+ :proxy_host => nil,
53
+ :proxy_port => nil,
54
+ :format => :json,
55
+ :application_name => 'Top4R',
56
+ :application_key => '12000224',
57
+ :application_secret => '2f26cb1a99570aa72daee12a1db88e63',
58
+ :application_version => Top4R::Version.to_version,
59
+ :application_url => 'http://top4r.nowa.me',
60
+ :user_agent => 'default',
61
+ :source => 'top4r'
62
+ }
63
+ @@config = Top4R::Config.new(@@defaults)
64
+
65
+ # Top4R::Client class methods
66
+ class << self
67
+ # Yields to given <tt>block</tt> to configure the Twitter4R API.
68
+ def configure(&block)
69
+ raise ArgumentError, "Block must be provided to configure" unless block_given?
70
+ yield @@config
71
+ end # configure
72
+ end # class << self
73
+ end # Client class
74
+ end
@@ -0,0 +1,29 @@
1
+ require 'optparse'
2
+
3
+ module Top4R
4
+ class Client
5
+ class << self
6
+ # Helper method mostly for irb shell prototyping.
7
+ #
8
+ # Reads in app_key/app_secret from YAML file
9
+ # found at the location given by <tt>config_file</tt> that has
10
+ # the following format:
11
+ # envname:
12
+ # app_key: application key
13
+ # app_secret: application secret
14
+ #
15
+ #
16
+ # Where <tt>envname</tt> is the name of the environment like 'test',
17
+ # 'dev' or 'prod'. The <tt>env</tt> argument defaults to 'test'.
18
+ #
19
+ # To use this in the shell you would do something like the following
20
+ # examples:
21
+ # top = Top4R::Client.from_config('config/top.yml', 'dev')
22
+ # top = Top4R::Client.from_config('config/top.yml')
23
+ def from_config(config_file, env = 'test')
24
+ yaml_hash = YAML.load(File.read(config_file))
25
+ self.new yaml_hash[env]
26
+ end
27
+ end # class << self
28
+ end
29
+ end
data/lib/top4r/core.rb ADDED
@@ -0,0 +1,57 @@
1
+ module Top4R
2
+ # Core
3
+ module ClassUtilMixin
4
+ module ClassMethods
5
+
6
+ end
7
+
8
+ module InstanceMethods
9
+ def initialize(params = {})
10
+ others = {}
11
+ params.each do |key,val|
12
+ if self.respond_to? key
13
+ self.send("#{key}=", val)
14
+ else
15
+ others[key] = val
16
+ end
17
+ end
18
+ self.send("#{:other_attrs}=", others) if self.respond_to? :other_attrs and others.size > 0
19
+ self.send(:init) if self.respond_to? :init
20
+ end
21
+
22
+ protected
23
+ def require_block(block_given)
24
+ raise ArgumentError, "Must provide a block" unless block_given
25
+ end
26
+ end
27
+
28
+ def self.included(receiver)
29
+ receiver.extend ClassMethods
30
+ receiver.send :include, InstanceMethods
31
+ end
32
+ end # ClassUtilMixin module
33
+
34
+ class RESTError < RuntimeError
35
+ include ClassUtilMixin
36
+ @@ATTRIBUTES = [:code, :message, :uri, :error]
37
+ attr_accessor *@@ATTRIBUTES
38
+
39
+ # Returns string in following format:
40
+ # "HTTP #{@code}: #{@message} at #{@uri}"
41
+ # For example,
42
+ # "HTTP 404: Resource Not Found at /i_am_crap.json"
43
+ def to_s
44
+ "HTTP #{@code}: #{@message} at #{@uri}"
45
+ end
46
+ end # RESTError
47
+
48
+ class LoginRequiredError < RuntimeError
49
+ include ClassUtilMixin
50
+ @@ATTRIBUTES = [:model, :method]
51
+ attr_accessor *@@ATTRIBUTES
52
+
53
+ def to_s
54
+ "#{@method} method at model #{@model} requires you to be logged in first"
55
+ end
56
+ end # LoginRequiredError
57
+ end
@@ -0,0 +1,17 @@
1
+ # Extension to Hash to create URL encoded string from key-values
2
+ class Hash
3
+ # Returns string formatted for HTTP URL encoded name-value pairs.
4
+ # For example,
5
+ # {:id => 'thomas_hardy'}.to_http_str
6
+ # # => "id=thomas_hardy"
7
+ # {:id => 23423, :since => Time.now}.to_http_str
8
+ # # => "since=Thu,%2021%20Jun%202007%2012:10:05%20-0500&id=23423"
9
+ def to_http_str
10
+ result = ''
11
+ return result if self.empty?
12
+ self.each do |key, val|
13
+ result << "#{key}=#{CGI.escape(val.to_s)}&"
14
+ end
15
+ result.chop # remove the last '&' character, since it can be discarded
16
+ end
17
+ end
data/lib/top4r/ext.rb ADDED
@@ -0,0 +1 @@
1
+ require_local('top4r/ext/stdlib')
data/lib/top4r/meta.rb ADDED
@@ -0,0 +1,56 @@
1
+ # meta.rb contains <tt>Twitter::Meta</tt> and related classes that
2
+ # help define the metadata of the <tt>Twitter4R</tt> project.
3
+
4
+ require('rubygems')
5
+ require('erb')
6
+
7
+ class Top4R::Meta #:nodoc:
8
+ attr_accessor :root_dir
9
+ attr_reader :gem_spec, :project_files, :spec_files
10
+
11
+ # Initializer for Twitter::Meta class. Takes <tt>root_dir</tt> as parameter.
12
+ def initialize(root_dir)
13
+ @root_dir = root_dir
14
+ end
15
+
16
+ # Returns package information defined in <tt>root_dir</tt>/pkg-info.yml
17
+ def pkg_info
18
+ yaml_file = File.join(@root_dir, 'pkg-info.yml')
19
+ ryaml = ERB.new(File.read(yaml_file), 0)
20
+ s = ryaml.result(binding)
21
+ YAML.load(s)
22
+ end
23
+
24
+ # Returns RubyGems spec information
25
+ def spec_info
26
+ self.pkg_info['spec'] if self.pkg_info
27
+ end
28
+
29
+ # Returns list of project files
30
+ def project_files
31
+ @project_files ||= Dir.glob(File.join(@root_dir, 'lib/**/*.rb'))
32
+ @project_files
33
+ end
34
+
35
+ # Returns list of specification files
36
+ def spec_files
37
+ @spec_files ||= Dir.glob(File.join(@root_dir, 'spec/**/*_spec.rb'))
38
+ @spec_files
39
+ end
40
+
41
+ # Returns RubyGem specification for Twitter4R project
42
+ def gem_spec
43
+ @gem_spec ||= Gem::Specification.new do |spec|
44
+ self.spec_info.each do |key, val|
45
+ if val.is_a?(Hash)
46
+ val.each do |k, v|
47
+ spec.send(key, k, v)
48
+ end
49
+ else
50
+ spec.send("#{key}=", val)
51
+ end
52
+ end
53
+ end
54
+ @gem_spec
55
+ end
56
+ end
@@ -0,0 +1,76 @@
1
+ module Top4R
2
+ # Area model
3
+ class Area
4
+ include ModelMixin
5
+ @@ATTRIBUTES = [:id, :area_id, :area_type, :area_name, :parent_id, :zip]
6
+ attr_accessor *@@ATTRIBUTES
7
+
8
+ class << self
9
+ def attributes; @@ATTRIBUTES; end
10
+
11
+ def default_public_fields
12
+ ["area_id", "area_type", "area_name", "parent_id", "zip"]
13
+ end
14
+ end
15
+
16
+ def unmarshal_other_attrs
17
+ @id = @area_id
18
+ self
19
+ end
20
+ end
21
+
22
+ # LogisticCompany model
23
+ class LogisticCompany
24
+ include ModelMixin
25
+ @@ATTRIBUTES = [:id, :company_id, :company_code, :company_name]
26
+ attr_accessor *@@ATTRIBUTES
27
+
28
+ class << self
29
+ def attributes; @@ATTRIBUTES; end
30
+
31
+ def default_public_fields
32
+ ["company_id", "company_code", "company_name"]
33
+ end
34
+ end
35
+
36
+ def unmarshal_other_attrs
37
+ @id = @company_id
38
+ self
39
+ end
40
+ end
41
+
42
+ # Delivery model
43
+ class Delivery
44
+ include ModelMixin
45
+ @@ATTRIBUTES = [:tid, :order_type, :company_code, :out_sid, :seller_name, :seller_area_id,
46
+ :seller_address, :seller_zip, :seller_phone, :seller_mobile, :memo]
47
+ attr_accessor *@@ATTRIBUTES
48
+
49
+ class << self
50
+ def attributes; @@ATTRIBUTES; end
51
+ end
52
+ end # Delivery model
53
+
54
+ # Shipping model
55
+ class Shipping
56
+ include ModelMixin
57
+ @@ATTRIBUTES = [:id, :tid, :seller_nick, :buyer_nick, :delivery_start, :delivery_end,
58
+ :out_sid, :item_title, :receiver_name, :receiver_phone, :receiver_mobile, :receiver_location,
59
+ :status, :type, :freight_payer, :seller_confirm, :company_name]
60
+ attr_accessor *@@ATTRIBUTES
61
+
62
+ class << self
63
+ def attributes; @@ATTRIBUTES; end
64
+ end
65
+
66
+ def unmarshal_other_attrs
67
+ @id = @out_sid
68
+ if @receiver_location && @receiver_location.size > 0
69
+ @receiver_location = Location.new(@receiver_location)
70
+ else
71
+ @receiver_location = nil
72
+ end
73
+ self
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,17 @@
1
+ module Top4R
2
+ # Suite model
3
+ class Suite
4
+ include ModelMixin
5
+ @@ATTRIBUTES = [:id, :nick, :suite_name, :start_date, :end_date]
6
+ attr_accessor *@@ATTRIBUTES
7
+
8
+ class << self
9
+ def attributes; @@ATTRIBUTES; end
10
+ end
11
+
12
+ def unmarshal_other_attrs
13
+ @id = 0
14
+ self
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,109 @@
1
+ module Top4R
2
+ # Order model
3
+ class Order
4
+ include ModelMixin
5
+ @@ATTRIBUTES = [:id, :iid, :sku_id, :sku_properties_name, :item_meal_name, :num, :title,
6
+ :price, :pic_path, :seller_nick, :buyer_nick, :type, :created, :refund_status, :tid,
7
+ :outer_iid, :outer_sku_id, :total_fee, :payment, :discount_fee, :adjust_fee, :status,
8
+ :snapshot_url, :timeout_action_time]
9
+ attr_accessor *@@ATTRIBUTES
10
+
11
+ class << self
12
+ def attributes; @@ATTRIBUTES; end
13
+
14
+ def default_public_fields
15
+ ["orders.title", "orders.price", "orders.num", "orders.iid", "orders.status", "orders.tid",
16
+ "orders.total_fee", "orders.payment", "orders.pic_path"]
17
+ end
18
+ end
19
+
20
+ def confirm_fees
21
+ @client.trade(@tid, :confirmfee, {:is_detail => "IS_CHILD"})
22
+ end
23
+
24
+ def unmarshal_other_attrs
25
+ @id = 0
26
+ self
27
+ end
28
+ end
29
+
30
+ # TradeConfirmFee model
31
+ class TradeConfirmFee
32
+ include ModelMixin
33
+ @@ATTRIBUTES = [:id, :confirm_fee, :confirm_post_fee, :is_last_detail_order]
34
+ attr_accessor *@@ATTRIBUTES
35
+
36
+ class << self
37
+ def attributes; @@ATTRIBUTES; end
38
+ end
39
+
40
+ def unmarshal_other_attrs
41
+ @id = 0
42
+ self
43
+ end
44
+ end
45
+
46
+ # Trade model
47
+ class Trade
48
+ include ModelMixin
49
+ @@ATTRIBUTES = [:id, :seller_nick, :buyer_nick, :title, :type, :created, :iid, :price,
50
+ :pic_path, :num, :tid, :buyer_message, :sid, :shipping_type, :alipay_no, :payment,
51
+ :discount_fee, :adjust_fee, :snapshot_url, :status, :seller_rate, :buyer_rate,
52
+ :buyer_memo, :seller_memo, :pay_time, :end_time, :modified, :buyer_obtain_point_fee,
53
+ :point_fee, :real_point_fee, :total_fee, :post_fee, :buyer_alipay_no, :receiver_name,
54
+ :receiver_state, :receiver_city, :receiver_district, :receiver_address, :receiver_zip,
55
+ :receiver_mobile, :receiver_phone, :consign_time, :buyer_email, :commission_fee,
56
+ :seller_alipay_no, :seller_mobile, :seller_phone, :seller_name, :seller_email,
57
+ :available_confirm_fee, :has_postFee, :received_payment, :cod_fee, :timeout_action_time, :orders]
58
+ attr_accessor *@@ATTRIBUTES
59
+
60
+ class << self
61
+ def attributes; @@ATTRIBUTES; end
62
+
63
+ def default_public_fields
64
+ ["buyer_nick", "seller_nick", "tid", "modified", "title", "type", "status", "created", "price",
65
+ "sid", "pic_path", "iid", "payment", "alipay_no", "shipping_type", "pay_time", "end_time",
66
+ "orders"] + Top4R::Order.default_public_fields
67
+ end
68
+ end
69
+
70
+ def close(reason = "现关闭本交易!")
71
+ @client.trade(@tid, :close, {:close_reason => reason})
72
+ end
73
+
74
+ def add_memo(memo)
75
+ valid_memo(memo)
76
+ @client.trade(@tid, :add_memo, {:memo => memo})
77
+ end
78
+
79
+ def update_memo(memo)
80
+ valid_memo(memo)
81
+ @client.trade(@tid, :update_memo, {:memo => memo})
82
+ end
83
+
84
+ def confirm_fees
85
+ @client.trade(@tid, :confirmfee, {:is_detail => "IS_FATHER"})
86
+ end
87
+
88
+ def deliver(options = {}, &block)
89
+ delivery = Delivery.new(options)
90
+ yield delivery if block_given?
91
+ delivery.tid = @tid
92
+ @client.deliver_trade(delivery)
93
+ end
94
+
95
+ def unmarshal_other_attrs
96
+ @id = @tid
97
+ if @orders.is_a?(Array)
98
+ @orders = @orders.map{|order| Order.new(order)}
99
+ end
100
+ self
101
+ end
102
+
103
+ private
104
+ def valid_memo(memo)
105
+ raise ArgumentError, "Invalid param: memo" if memo
106
+ raise ArgumentError, "Invalid param length: Memo must be less than 1000 characters" if memo.size > 1000
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,92 @@
1
+ module Top4R
2
+ module LoggedInUserMixin
3
+ module InstanceMethods
4
+ def trades(method = :bought_list, options = {})
5
+ @client.trades_for(method, options)
6
+ end
7
+
8
+ def suites(service_code, options = {})
9
+ @client.suites(self.nick, service_code, :list, options)
10
+ end
11
+ end
12
+
13
+ def self.included(receiver)
14
+ receiver.send :include, InstanceMethods
15
+ end
16
+ end # LoggedInUserMixin module
17
+
18
+ # Location Model
19
+ class Location
20
+ include ModelMixin
21
+ @@ATTRIBUTES = [:zip, :address, :city, :state, :country, :district]
22
+ attr_accessor *@@ATTRIBUTES
23
+
24
+ class << self
25
+ def attributes
26
+ @@ATTRIBUTES
27
+ end
28
+ end
29
+ end # Location model
30
+
31
+ # UserCredit Model
32
+ class UserCredit
33
+ include ModelMixin
34
+ @@ATTRIBUTES = [:level, :score, :total_num, :good_num]
35
+ attr_accessor *@@ATTRIBUTES
36
+
37
+ class << self
38
+ def attributes; @@ATTRIBUTES; end
39
+ end
40
+ end # UserCredit model
41
+
42
+ # User Model
43
+ class User
44
+ include ModelMixin
45
+ @@ATTRIBUTES = [:id, :user_id, :nick, :sex, :buyer_credit, :seller_credit, :location,
46
+ :created, :last_visit, :birthday, :type, :has_more_pic, :item_img_num, :item_img_size,
47
+ :prop_img_num, :prop_img_size, :auto_repost, :promoted_type, :status, :alipay_bind,
48
+ :consumer_protection, :other_attrs]
49
+ attr_accessor *@@ATTRIBUTES
50
+
51
+ class << self
52
+ def attributes; @@ATTRIBUTES; end
53
+
54
+ def default_public_fields
55
+ ["user_id", "nick", "sex", "buyer_credit", "seller_credit",
56
+ "location.city", "location.state", "location.country", "created", "last_visit"]
57
+ end
58
+
59
+ def default_private_fields
60
+ ["location.zip", "birthday"]
61
+ end
62
+
63
+ def find(u, client)
64
+ client.user(u)
65
+ end
66
+ end
67
+
68
+ def bless(client)
69
+ basic_bless(client)
70
+ self.instance_eval(%{
71
+ self.class.send(:include, Top4R::LoggedInUserMixin)
72
+ }) if self.is_me? and not self.respond_to?(:trades)
73
+ self
74
+ end
75
+
76
+ def is_me?
77
+ @nick == @client.instance_eval("@parameters['visitor_nick']")
78
+ end
79
+
80
+ def unmarshal_other_attrs
81
+ @id = @user_id
82
+ if @location && @location.size > 0
83
+ @location = Location.new(@location)
84
+ else
85
+ @location = nil
86
+ end
87
+ @buyer_credit = UserCredit.new(@buyer_credit) if @buyer_credit && @buyer_credit.size > 0
88
+ @seller_credit = UserCredit.new(@seller_credit) if @seller_credit && @seller_credit.size > 0
89
+ self
90
+ end
91
+ end # User model
92
+ end
@@ -0,0 +1,111 @@
1
+ module Top4R
2
+ module ModelMixin
3
+ module ClassMethods
4
+ def default_public_fields; []; end
5
+
6
+ def default_private_fields; []; end
7
+
8
+ # Unmarshal object singular or plural array of model objects
9
+ # from JSON serialization. Currently JSON is only supported.
10
+ def unmarshal(raw)
11
+ # input = JSON.parse(raw)
12
+ input = raw
13
+ # puts "\ninput: #{input.inspect}"
14
+ def unmarshal_model(hash)
15
+ mine = self.new(hash)
16
+ # puts "\n mine: #{mine.inspect}"
17
+ mine.unmarshal_other_attrs if mine.respond_to? :unmarshal_other_attrs
18
+ mine
19
+ end
20
+ return unmarshal_model(input) if input.is_a?(Hash) # singular case
21
+ result = []
22
+ input.each do |hash|
23
+ model = unmarshal_model(hash) if hash.is_a?(Hash)
24
+ result << model
25
+ end if input.is_a?(Array)
26
+ result # plural case
27
+ end
28
+
29
+ def fields
30
+ (self.default_public_fields + self.default_private_fields).uniq.join(',')
31
+ end
32
+ end
33
+
34
+ module InstanceMethods
35
+ attr_accessor :client
36
+
37
+ # Equality method override of Object#eql? default.
38
+ #
39
+ # Relies on the class using this mixin to provide a <tt>attributes</tt>
40
+ # class method that will return an Array of attributes to check are
41
+ # equivalent in this #eql? override.
42
+ #
43
+ # It is by design that the #eql? method will raise a NoMethodError
44
+ # if no <tt>attributes</tt> class method exists, to alert you that
45
+ # you must provide it for a meaningful result from this #eql? override.
46
+ # Otherwise this will return a meaningless result.
47
+ def eql?(other)
48
+ attrs = self.class.attributes
49
+ attrs.each do |att|
50
+ return false unless self.send(att).eql?(other.send(att))
51
+ end
52
+ true
53
+ end
54
+
55
+ # Returns integer representation of model object instance.
56
+ #
57
+ # For example,
58
+ # product = Top4R::Product.new(:id => 234343)
59
+ # product.to_i #=> 234343
60
+ def to_i
61
+ @id
62
+ end
63
+
64
+ # Returns hash representation of model object instance.
65
+ #
66
+ # For example,
67
+ # u = Top4R::User.new(:id => 2342342, :screen_name => 'tony_blair_is_the_devil')
68
+ # u.to_hash #=> {:id => 2342342, :screen_name => 'tony_blair_is_the_devil'}
69
+ #
70
+ # This method also requires that the class method <tt>attributes</tt> be
71
+ # defined to return an Array of attributes for the class.
72
+ def to_hash
73
+ attrs = self.class.attributes
74
+ result = {}
75
+ attrs.each do |att|
76
+ value = self.send(att)
77
+ value = value.to_hash if value.respond_to?(:to_hash)
78
+ result[att] = value if value
79
+ end
80
+ result
81
+ end
82
+
83
+ # "Blesses" model object.
84
+ #
85
+ # Should be overridden by model class if special behavior is expected
86
+ #
87
+ # Expected to return blessed object (usually <tt>self</tt>)
88
+ def bless(client)
89
+ self.basic_bless(client)
90
+ end
91
+
92
+ protected
93
+ # Basic "blessing" of model object
94
+ def basic_bless(client)
95
+ self.client = client
96
+ self
97
+ end
98
+ end
99
+
100
+ def self.included(receiver)
101
+ receiver.extend ClassMethods
102
+ receiver.send :include, Top4R::ClassUtilMixin
103
+ receiver.send :include, InstanceMethods
104
+ end
105
+ end # ModelMixin module
106
+ end
107
+
108
+ require 'top4r/model/user'
109
+ require 'top4r/model/shipping'
110
+ require 'top4r/model/trade'
111
+ require 'top4r/model/suite'
@@ -0,0 +1,17 @@
1
+ module Top4R::Version
2
+ MAJOR = 0
3
+ MINOR = 0
4
+ REVISION = 1
5
+
6
+ class << self
7
+ # Returns X.Y.Z formatted version string
8
+ def to_version
9
+ "#{MAJOR}.#{MINOR}.#{REVISION}"
10
+ end
11
+
12
+ # Returns X-Y-Z formatted version name
13
+ def to_name
14
+ "#{MAJOR}_#{MINOR}_#{REVISION}"
15
+ end
16
+ end
17
+ end
data/lib/top4r.rb ADDED
@@ -0,0 +1,26 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ module Top4R; end
4
+
5
+ def require_local(suffix)
6
+ require(File.expand_path(File.join(File.dirname(__FILE__), suffix)))
7
+ end
8
+
9
+ require 'digest/md5'
10
+ require 'net/http'
11
+ require 'net/https'
12
+ require 'uri'
13
+ require 'cgi'
14
+ require 'json'
15
+ require 'yaml'
16
+ require 'iconv'
17
+ require 'activesupport'
18
+
19
+ require_local('top4r/ext')
20
+ require_local('top4r/version')
21
+ require_local('top4r/meta')
22
+ require_local('top4r/core')
23
+ require_local('top4r/model')
24
+ require_local('top4r/config')
25
+ require_local('top4r/client')
26
+ require_local('top4r/console')
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nowa-top4r
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nowa Zhu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.1
24
+ version:
25
+ description:
26
+ email: nowazhu@gmail.com
27
+ executables:
28
+ - top4rsh
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ - CHANGES
34
+ - TODO
35
+ - MIT-LICENSE
36
+ files:
37
+ - lib/top4r/client/base.rb
38
+ - lib/top4r/client/shipping.rb
39
+ - lib/top4r/client/suite.rb
40
+ - lib/top4r/client/trade.rb
41
+ - lib/top4r/client/user.rb
42
+ - lib/top4r/client.rb
43
+ - lib/top4r/config.rb
44
+ - lib/top4r/console.rb
45
+ - lib/top4r/core.rb
46
+ - lib/top4r/ext/stdlib.rb
47
+ - lib/top4r/ext.rb
48
+ - lib/top4r/meta.rb
49
+ - lib/top4r/model/shipping.rb
50
+ - lib/top4r/model/suite.rb
51
+ - lib/top4r/model/trade.rb
52
+ - lib/top4r/model/user.rb
53
+ - lib/top4r/model.rb
54
+ - lib/top4r/version.rb
55
+ - lib/top4r.rb
56
+ - README
57
+ - CHANGES
58
+ - TODO
59
+ - MIT-LICENSE
60
+ has_rdoc: true
61
+ homepage: http://top4r.labs.nowa.me
62
+ licenses:
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project: top4r
83
+ rubygems_version: 1.3.5
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: TOP4R is a library that can help you build plugin for TaoBao.com quickly in pure Ruby.
87
+ test_files: []
88
+