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 +5 -0
- data/MIT-LICENSE +20 -0
- data/README +20 -0
- data/TODO +0 -0
- data/lib/top4r/client/base.rb +148 -0
- data/lib/top4r/client/shipping.rb +45 -0
- data/lib/top4r/client/suite.rb +17 -0
- data/lib/top4r/client/trade.rb +48 -0
- data/lib/top4r/client/user.rb +31 -0
- data/lib/top4r/client.rb +23 -0
- data/lib/top4r/config.rb +87 -0
- data/lib/top4r/console.rb +29 -0
- data/lib/top4r/core.rb +63 -0
- data/lib/top4r/ext/stdlib.rb +27 -0
- data/lib/top4r/ext.rb +1 -0
- data/lib/top4r/logger.rb +24 -0
- data/lib/top4r/meta.rb +56 -0
- data/lib/top4r/model/shipping.rb +76 -0
- data/lib/top4r/model/suite.rb +17 -0
- data/lib/top4r/model/trade.rb +109 -0
- data/lib/top4r/model/user.rb +93 -0
- data/lib/top4r/model.rb +111 -0
- data/lib/top4r/version.rb +17 -0
- data/lib/top4r.rb +28 -0
- metadata +90 -0
data/CHANGES
ADDED
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
|
data/lib/top4r/client.rb
ADDED
@@ -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'
|
data/lib/top4r/config.rb
ADDED
@@ -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')
|
data/lib/top4r/logger.rb
ADDED
@@ -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
|
data/lib/top4r/model.rb
ADDED
@@ -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
|
+
|