top4r 0.0.24

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/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
@@ -0,0 +1,148 @@
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
+ @@logger = Top4R::Logger.new(@@config.logger, @@config.trace)
14
+ if @parameters and @session
15
+ @parameters = Base64.decode64(@parameters).split('&').inject({}) do |hsh, i| kv = i.split('='); hsh[kv[0]] = kv[1]; hsh end
16
+ @login = user(@parameters['visitor_nick'].to_utf8)
17
+ # puts "login: #{@login.inspect}"
18
+ end
19
+ end
20
+
21
+ protected
22
+ attr_accessor :app_key, :app_secret, :parameters, :session
23
+
24
+ def login_required(model, method)
25
+ return if logged_in?
26
+ raise Top4R::LoginRequiredError.new({:model => model, :method => method})
27
+ end
28
+
29
+ def http_connect(body=nil, &block)
30
+ require_block(block_given?)
31
+ connection = create_http_connection
32
+ connection.start do |connection|
33
+ request = yield connection if block_given?
34
+ # puts "conn: #{connection.inspect}"
35
+ # puts "request: #{request.inspect}"
36
+ timeout(15) do
37
+ response = connection.request(request, body)
38
+ @@logger.info "response: #{response.body}"
39
+ end
40
+ handle_rest_response(response)
41
+ response
42
+ end
43
+ end
44
+
45
+ # "Blesses" model object with client information
46
+ def bless_model(model)
47
+ model.bless(self) if model
48
+ end
49
+
50
+ def bless_models(list)
51
+ return bless_model(list) if list.respond_to?(:client=)
52
+ list.collect { |model| bless_model(model) } if list.respond_to?(:collect)
53
+ end
54
+
55
+ private
56
+ @@http_header = nil
57
+
58
+ def valid_method(method, methods, model, force_login = false)
59
+ 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
60
+ raise ArgumentError, "Invalid #{model} method: #{method}" unless methods.keys.member?(method)
61
+ end
62
+
63
+ def raise_rest_error(response, uri = nil)
64
+ map = JSON.parse(response.body)
65
+ raise Top4R::RESTError.new(:code => response.code,
66
+ :message => response.message,
67
+ :error => map["error_rsp"],
68
+ :uri => uri)
69
+ end
70
+
71
+ def handle_rest_response(response, uri = nil)
72
+ unless response.is_a?(Net::HTTPSuccess)
73
+ raise_rest_error(response, uri)
74
+ end
75
+
76
+ map = JSON.parse(response.body)
77
+ if map["error_rsp"].is_a?(Hash) and map["error_rsp"]["code"].to_s == "630"
78
+ @@logger.info "Raising SuiteNotOrderedError..."
79
+ raise Top4R::SuiteNotOrderedError.new(:code => map["error_rsp"]["code"],
80
+ :message => map["error_rsp"]["msg"],
81
+ :error => map["error_rsp"],
82
+ :uri => uri)
83
+ elsif map["error_rsp"].is_a?(Hash)
84
+ @@logger.info "Raising RESTError..."
85
+ raise Top4R::RESTError.new(:code => map["error_rsp"]["code"],
86
+ :message => map["error_rsp"]["msg"],
87
+ :error => map["error_rsp"],
88
+ :uri => uri)
89
+ end
90
+ end
91
+
92
+ def create_http_connection
93
+ 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)
94
+ @@logger.info "Host: #{host}\nPort: #{port}\n"
95
+ conn = Net::HTTP.new(host, port,
96
+ @@config.proxy_host, @@config.proxy_port,
97
+ @@config.proxy_user, @@config.proxy_pass)
98
+ if protocol == :ssl
99
+ conn.use_ssl = true
100
+ conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
101
+ end
102
+ conn
103
+ end
104
+
105
+ def http_header
106
+ # can cache this in class variable since all "variables" used to
107
+ # create the contents of the HTTP header are determined by other
108
+ # class variables that are not designed to change after instantiation.
109
+ @@http_header ||= {
110
+ 'User-Agent' => "Top4R v#{Top4R::Version.to_version} [#{@@config.user_agent}]",
111
+ 'Accept' => 'text/x-json',
112
+ 'X-TOP-Client' => @@config.application_name,
113
+ 'X-TOP-Client-Version' => @@config.application_version,
114
+ 'X-TOP-Client-URL' => @@config.application_url,
115
+ }
116
+ @@http_header
117
+ end
118
+
119
+ def append_top_params(params)
120
+ params = params.merge({
121
+ :session => @session,
122
+ :timestamp => Time.now.strftime("%Y-%m-%d %H:%M:%S"),
123
+ :format => "#{@@config.format}",
124
+ :app_key => @app_key,
125
+ :v => "1.0"
126
+ })
127
+ params = params.merge({
128
+ :sign => Digest::MD5.hexdigest(params.sort {|a,b| "#{a[0]}"<=>"#{b[0]}"}.flatten.unshift(@app_secret).join).upcase
129
+ })
130
+ end
131
+
132
+ def create_http_get_request(method, params = {})
133
+ uri = @@config.env == :production ? @@config.rest_uri : @@config.test_rest_uri
134
+ params = append_top_params(params.merge({:method => method}))
135
+ path = (params.size > 0) ? "#{uri}?#{params.to_http_str}" : uri
136
+ @@logger.info "path: #{path}"
137
+ Net::HTTP::Get.new(path, http_header)
138
+ end
139
+
140
+ def create_http_post_request(uri)
141
+ Net::HTTP::Post.new(uri, http_header)
142
+ end
143
+
144
+ def create_http_delete_request(uri, params = {})
145
+ path = (params.size > 0) ? "#{uri}?#{params.to_http_str}" : uri
146
+ Net::HTTP::Delete.new(path, http_header)
147
+ end
148
+ 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"]["suites"])
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,87 @@
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
+ # :staging_host,
16
+ # :staging_rest_uri,
17
+ # :staging_port,
18
+ # :staging_protocol,
19
+ :proxy_host,
20
+ :proxy_port,
21
+ :proxy_user,
22
+ :proxy_pass,
23
+ :format,
24
+ :application_name,
25
+ :application_key,
26
+ :application_secret,
27
+ :application_version,
28
+ :application_url,
29
+ :user_agent,
30
+ :source,
31
+ :logger,
32
+ :trace
33
+ ]
34
+ attr_accessor *@@ATTRIBUTES
35
+
36
+ # Override of Object#eql? to ensure RSpec specifications run
37
+ # correctly. Also done to follow Ruby best practices.
38
+ def eql?(other)
39
+ return true if self == other
40
+ @@ATTRIBUTES.each do |att|
41
+ return false unless self.send(att).eql?(other.send(att))
42
+ end
43
+ true
44
+ end
45
+ end # Config class
46
+
47
+ class Client
48
+ @@defaults = {
49
+ :env => :test,
50
+ :host => 'gw.api.taobao.com',
51
+ :rest_uri => '/router/rest',
52
+ :port => 80,
53
+ :protocol => :http,
54
+ :test_host => 'gw.sandbox.taobao.com',
55
+ :test_rest_uri => '/router/rest',
56
+ :test_port => 80,
57
+ :test_protocol => :http,
58
+ # :staging_host => '192.168.208.110',
59
+ # :staging_rest_uri => '/top/private/services/rest',
60
+ # :staging_port => '8080',
61
+ # :staging_protocol => :http,
62
+ :proxy_host => nil,
63
+ :proxy_port => nil,
64
+ :format => :json,
65
+ :application_name => 'Top4R',
66
+ :application_key => '12000224',
67
+ :application_secret => '2f26cb1a99570aa72daee12a1db88e63',
68
+ :application_version => Top4R::Version.to_version,
69
+ :application_url => 'http://top4r.nowa.me',
70
+ :user_agent => 'default',
71
+ :source => 'top4r',
72
+ :logger => nil,
73
+ :trace => false
74
+ }
75
+ @@config = Top4R::Config.new(@@defaults)
76
+ @@logger = Top4R::Logger.new(@@config.logger)
77
+
78
+ # Top4R::Client class methods
79
+ class << self
80
+ # Yields to given <tt>block</tt> to configure the Twitter4R API.
81
+ def configure(&block)
82
+ raise ArgumentError, "Block must be provided to configure" unless block_given?
83
+ yield @@config
84
+ end # configure
85
+ end # class << self
86
+ end # Client class
87
+ 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,63 @@
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 SuiteNotOrderedError < RESTError
49
+ def to_s
50
+ "错误代号#{@code},您没有订购该服务!"
51
+ end
52
+ end
53
+
54
+ class LoginRequiredError < RuntimeError
55
+ include ClassUtilMixin
56
+ @@ATTRIBUTES = [:model, :method]
57
+ attr_accessor *@@ATTRIBUTES
58
+
59
+ def to_s
60
+ "#{@method} method at model #{@model} requires you to be logged in first"
61
+ end
62
+ end # LoginRequiredError
63
+ end
@@ -0,0 +1,27 @@
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
18
+
19
+ class String
20
+ def to_gbk
21
+ Iconv.iconv("GBK//IGNORE", "UTF-8//IGNORE", self).to_s
22
+ end
23
+
24
+ def to_utf8
25
+ Iconv.iconv("UTF-8//IGNORE", "GBK//IGNORE", self).to_s
26
+ end
27
+ end
data/lib/top4r/ext.rb ADDED
@@ -0,0 +1 @@
1
+ require_local('top4r/ext/stdlib')
@@ -0,0 +1,24 @@
1
+ class Top4R::Logger
2
+ attr_accessor :trace
3
+
4
+ class << self
5
+ def set_logger(logger)
6
+ self.new logger
7
+ end
8
+ end
9
+
10
+ class Nogger
11
+ def info(log)
12
+ puts log
13
+ end
14
+ end
15
+
16
+ def initialize(logger, is_trace = false)
17
+ @trace = is_trace
18
+ @logger = logger || Nogger.new
19
+ end
20
+
21
+ def info(log)
22
+ @logger.info "top4r trace: #{log}" if @trace
23
+ end
24
+ end
data/lib/top4r/meta.rb ADDED
@@ -0,0 +1,56 @@
1
+ # meta.rb contains <tt>Top4R::Meta</tt> and related classes that
2
+ # help define the metadata of the <tt>Top4R</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 Top4R::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 Top4R 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,93 @@
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", "type"]
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']").to_utf8
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
+ # @nick = @nick.to_utf8
90
+ self
91
+ end
92
+ end # User model
93
+ 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 = 24
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,28 @@
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
+ require 'timeout'
19
+
20
+ require_local('top4r/ext')
21
+ require_local('top4r/version')
22
+ require_local('top4r/logger')
23
+ require_local('top4r/meta')
24
+ require_local('top4r/core')
25
+ require_local('top4r/model')
26
+ require_local('top4r/config')
27
+ require_local('top4r/client')
28
+ require_local('top4r/console')
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: top4r
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.24
5
+ platform: ruby
6
+ authors:
7
+ - Nowa Zhu
8
+ autorequire: top4r
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-15 00:00:00 +08: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
+
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/logger.rb
49
+ - lib/top4r/meta.rb
50
+ - lib/top4r/model/shipping.rb
51
+ - lib/top4r/model/suite.rb
52
+ - lib/top4r/model/trade.rb
53
+ - lib/top4r/model/user.rb
54
+ - lib/top4r/model.rb
55
+ - lib/top4r/version.rb
56
+ - lib/top4r.rb
57
+ - README
58
+ - CHANGES
59
+ - TODO
60
+ - MIT-LICENSE
61
+ has_rdoc: true
62
+ homepage: http://top4r.labs.nowa.me
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options: []
67
+
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.8.2
75
+ version:
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ requirements:
83
+ - Ruby 1.8.4+
84
+ rubyforge_project: top4r
85
+ rubygems_version: 1.3.3
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: TOP4R is a library that can help you build plugin for TaoBao.com quickly in pure Ruby.
89
+ test_files: []
90
+