woahdae-consumer 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/LICENSE +20 -0
- data/Manifest.txt +73 -0
- data/PostInstall.txt +8 -0
- data/README.rdoc +53 -0
- data/Rakefile +30 -0
- data/app_generators/consumer/USAGE +14 -0
- data/app_generators/consumer/consumer_generator.rb +89 -0
- data/app_generators/consumer/templates/LICENSE +20 -0
- data/app_generators/consumer/templates/README.rdoc +3 -0
- data/app_generators/consumer/templates/Rakefile +57 -0
- data/app_generators/consumer/templates/TODO +4 -0
- data/app_generators/consumer/templates/config/config.yml +2 -0
- data/app_generators/consumer/templates/config/config.yml.sample +1 -0
- data/app_generators/consumer/templates/lib/base.rb +6 -0
- data/app_generators/consumer/templates/rails/init.rb +1 -0
- data/app_generators/consumer/templates/script/destroy +14 -0
- data/app_generators/consumer/templates/script/generate +14 -0
- data/app_generators/consumer/templates/spec/spec_helper.rb +11 -0
- data/bin/consumer +17 -0
- data/config/website.yml.sample +2 -0
- data/consumer.gemspec +48 -0
- data/consumer_generators/request/USAGE +25 -0
- data/consumer_generators/request/request_generator.rb +94 -0
- data/consumer_generators/request/templates/lib/request.rb +55 -0
- data/consumer_generators/request/templates/lib/response.rb +12 -0
- data/consumer_generators/request/templates/spec/request_spec.rb +27 -0
- data/consumer_generators/request/templates/spec/response_spec.rb +10 -0
- data/consumer_generators/request/templates/spec/xml/response.xml +0 -0
- data/examples/active_record/README.txt +1 -0
- data/examples/active_record/ar_spec.rb +33 -0
- data/examples/active_record/database.sqlite +0 -0
- data/examples/active_record/environment.rb +15 -0
- data/examples/active_record/migration.rb +21 -0
- data/examples/active_record/models/book.rb +13 -0
- data/examples/active_record/models/contributor.rb +12 -0
- data/examples/active_record/xml/book.xml +6 -0
- data/examples/active_record/xml/book_with_contributors.xml +11 -0
- data/examples/active_record/xml/contributor.xml +3 -0
- data/examples/active_record/xml/contributor_with_books.xml +19 -0
- data/examples/shipping/environment.rb +3 -0
- data/examples/shipping/rate.rb +15 -0
- data/examples/shipping/shipping.yml.sample +8 -0
- data/examples/shipping/shipping_spec.rb +27 -0
- data/examples/shipping/ups_rate_request.rb +182 -0
- data/examples/shipping/ups_rate_response.xml +340 -0
- data/lib/consumer/helper.rb +111 -0
- data/lib/consumer/mapping.rb +184 -0
- data/lib/consumer/request.rb +280 -0
- data/lib/consumer.rb +28 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +71 -0
- data/spec/helper_spec.rb +136 -0
- data/spec/mapping_spec.rb +94 -0
- data/spec/request_spec.rb +75 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/xml/rate_response.xml +14 -0
- data/spec/xml/rate_response_error.xml +35 -0
- data/tasks/rspec.rake +21 -0
- data/test/test_consumer_generator.rb +68 -0
- data/test/test_generator_helper.rb +29 -0
- data/website/index.html +11 -0
- data/website/index.txt +81 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +159 -0
- data/website/template.html.erb +50 -0
- metadata +180 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
# === Vendor API Docs
|
2
|
+
# http://www.example.com/handy_docs
|
3
|
+
class <%= "#{appname.camelcase}::#{request_class}" %> < Consumer::Request
|
4
|
+
|
5
|
+
### Note: Everything except to_xml is optional (though handy) ###
|
6
|
+
|
7
|
+
response_class "<%= response_class %>"
|
8
|
+
yaml_defaults "<%= appname %>.yml", "<%= request_base.underscore %>"
|
9
|
+
|
10
|
+
# If root is found in a response, code + message will be raised
|
11
|
+
error_paths({
|
12
|
+
:root => "//Error",
|
13
|
+
:code => "//ErrorCode",
|
14
|
+
:message => "//ErrorDescription"
|
15
|
+
})
|
16
|
+
|
17
|
+
# Instance variables that must be set before xml sendoff
|
18
|
+
def required
|
19
|
+
return [
|
20
|
+
# :required_attrs_array
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Lowest priority; overwritten by YAML, then params
|
25
|
+
def defaults
|
26
|
+
return {
|
27
|
+
# :sensible_default => "Value"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def url
|
32
|
+
return "www.example.com/testing" if $TESTING
|
33
|
+
|
34
|
+
"www.example.com"
|
35
|
+
end
|
36
|
+
|
37
|
+
def headers
|
38
|
+
{"SoapAction" => ""}
|
39
|
+
end
|
40
|
+
|
41
|
+
# Called before required vars are checked, too
|
42
|
+
def before_to_xml; end
|
43
|
+
|
44
|
+
# All this has to do is return xml, and we have a Builder instance to help.
|
45
|
+
# Also, defaults, YAML, and the params are accessed via instance variables.
|
46
|
+
def to_xml
|
47
|
+
b.instruct!
|
48
|
+
|
49
|
+
# docs at http://builder.rubyforge.org/classes/Builder/XmlMarkup.html
|
50
|
+
# example:
|
51
|
+
b.<%= request_class %> {
|
52
|
+
b.Hello "World"
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class <%= "#{appname.camelcase}::#{response_class}" %>
|
2
|
+
include Consumer::Mapping
|
3
|
+
attr_accessor :attribute
|
4
|
+
|
5
|
+
# This is fairly dense; see documentation for full explanation
|
6
|
+
# map(:all or :first, "root xpath", registry, opts = {}, &postprocessing)
|
7
|
+
map(:all, "//FullyQualified/Xpath/ToRoot", {
|
8
|
+
:attribute => "RelativeOrFQxPathToValue",
|
9
|
+
},
|
10
|
+
:include => [:association1, :association2]
|
11
|
+
) {|<%= response_class.underscore %>| <%= response_class.underscore%>.attribute.strip! }
|
12
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe <%= "#{appname.camelcase}::#{request_class}" %> do
|
4
|
+
|
5
|
+
it "creates xml" do
|
6
|
+
<%= request_class.underscore %> = <%= request_class %>.new({
|
7
|
+
# :attribute => value
|
8
|
+
})
|
9
|
+
xml = <%= request_class.underscore %>.to_xml_etc
|
10
|
+
xml.should =~ /\<\?xml/
|
11
|
+
end
|
12
|
+
|
13
|
+
# run "DO_IT_LIVE=true spec spec" to contact the api
|
14
|
+
if ENV['DO_IT_LIVE']
|
15
|
+
|
16
|
+
it "contacts the live api and returns <%= response_class %> instance(s)" do
|
17
|
+
$DEBUG = true # spit out xml for the request & response
|
18
|
+
|
19
|
+
<%= response_class.underscore %> = <%= request_class %>.new({
|
20
|
+
# :attribute => "value"
|
21
|
+
}).do
|
22
|
+
<%= response_class.underscore %>.should_not be_blank
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe <%= "#{appname.camelcase}::#{response_class}" %> do
|
4
|
+
it "should make an instance of itself via from_xml" do
|
5
|
+
file = "spec/xml/<%= response_xml %>"
|
6
|
+
xml = File.read("#{file}")
|
7
|
+
|
8
|
+
<%= response_class %>.from_xml(xml).should_not be_blank
|
9
|
+
end
|
10
|
+
end
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
This is an example focusing on maps in an active_record environment. Requests are irrelevant here, as they're not intended to ever be used with ActiveRecord (althogh nothing prevents it).
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'environment'
|
3
|
+
|
4
|
+
# Very broad tests to see ROXML working with Active Record
|
5
|
+
|
6
|
+
describe "ROXML in ActiveRecord" do
|
7
|
+
before(:all) do
|
8
|
+
@book_xml = File.read("xml/book.xml")
|
9
|
+
@book_with_contributors_xml = File.read("xml/book_with_contributors.xml")
|
10
|
+
@contributor_with_books_xml = File.read("xml/contributor_with_books.xml")
|
11
|
+
@contributor_xml = File.read("xml/contributor.xml")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "creates a valid AR object from xml" do
|
15
|
+
book = Book.from_xml(@book_xml)
|
16
|
+
book.isbn.should == "0974514055"
|
17
|
+
book.title.should == "Programming Ruby - 2nd Edition"
|
18
|
+
book.description.should == "Second edition of the great book out there"
|
19
|
+
book.save.should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "habtm for books-contributors" do
|
23
|
+
it "works from the book side of the relationship" do
|
24
|
+
book = Book.from_xml(@book_with_contributors_xml)
|
25
|
+
book.contributors.size.should == 3
|
26
|
+
end
|
27
|
+
|
28
|
+
it "works from the contributor side of the relationship" do
|
29
|
+
contributor = Contributor.from_xml(@contributor_with_books_xml)
|
30
|
+
contributor.books.size.should == 3
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
require 'sqlite3'
|
4
|
+
|
5
|
+
|
6
|
+
require File.dirname(__FILE__) + '/../../lib/consumer.rb'
|
7
|
+
|
8
|
+
$:.unshift(File.dirname(__FILE__))
|
9
|
+
require 'models/contributor'
|
10
|
+
require 'models/book'
|
11
|
+
|
12
|
+
ActiveRecord::Base.establish_connection(
|
13
|
+
:adapter => 'sqlite3',
|
14
|
+
:dbfile => 'database.sqlite'
|
15
|
+
)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/environment'
|
4
|
+
|
5
|
+
ActiveRecord::Schema.define do
|
6
|
+
create_table "books", :force => true do |t|
|
7
|
+
t.string :title
|
8
|
+
t.text :description
|
9
|
+
t.string :isbn
|
10
|
+
end
|
11
|
+
|
12
|
+
create_table "contributors", :force => true do |t|
|
13
|
+
t.string :name
|
14
|
+
t.string :role
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table "books_contributors", :force => true do |t|
|
18
|
+
t.integer :book_id
|
19
|
+
t.integer :contributor_id
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Book < ActiveRecord::Base
|
2
|
+
include Consumer::Mapping
|
3
|
+
has_and_belongs_to_many :contributors
|
4
|
+
|
5
|
+
@habtm_registry = {
|
6
|
+
:isbn => "attribute::isbn",
|
7
|
+
:title => "title",
|
8
|
+
:description => "description"
|
9
|
+
}
|
10
|
+
|
11
|
+
map(:first, "//BookResponse/book", @habtm_registry, :include => :contributors)
|
12
|
+
map(:all, "//ContributorResponse/contributor/books/book", @habtm_registry)
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Contributor < ActiveRecord::Base
|
2
|
+
include Consumer::Mapping
|
3
|
+
has_and_belongs_to_many :books
|
4
|
+
|
5
|
+
@habtm_registry = {
|
6
|
+
:role => "attribute::role",
|
7
|
+
:name => "name"
|
8
|
+
}
|
9
|
+
|
10
|
+
map(:first, "//ContributorResponse/contributor", @habtm_registry, :include => :books)
|
11
|
+
map(:all, "//BookResponse/book/contributors/contributor", @habtm_registry)
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<BookResponse>
|
2
|
+
<book isbn="0974514055">
|
3
|
+
<title>Programming Ruby - 2nd Edition</title>
|
4
|
+
<description>Second edition of the great book out there</description>
|
5
|
+
<contributors>
|
6
|
+
<contributor role="author"><name>David Thomas</name></contributor>
|
7
|
+
<contributor role="supporting author"><name>Andrew Hunt</name></contributor>
|
8
|
+
<contributor role="supporting author"><name>Chad Fowler</name></contributor>
|
9
|
+
</contributors>
|
10
|
+
</book>
|
11
|
+
</BookResponse>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<ContributorResponse>
|
2
|
+
<contributor role="author">
|
3
|
+
<name>David Thomas</name>
|
4
|
+
<books>
|
5
|
+
<book isbn="0974514055">
|
6
|
+
<title>Programming Ruby - 2nd Edition</title>
|
7
|
+
<description>Second edition of the great book out there</description>
|
8
|
+
</book>
|
9
|
+
<book isbn="1112223334">
|
10
|
+
<title>Hitchhikers Guide to the Galaxy</title>
|
11
|
+
<description>42</description>
|
12
|
+
</book>
|
13
|
+
<book isbn="4556677889">
|
14
|
+
<title>Cats</title>
|
15
|
+
<description>lol</description>
|
16
|
+
</book>
|
17
|
+
</books>
|
18
|
+
</contributor>
|
19
|
+
</ContributorResponse>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/environment"
|
2
|
+
|
3
|
+
class Rate
|
4
|
+
include Consumer::Mapping
|
5
|
+
attr_accessor :service, :code, :price, :carrier
|
6
|
+
|
7
|
+
# UPS
|
8
|
+
map(:all, "//RatingServiceSelectionResponse/RatedShipment", {
|
9
|
+
:price => "TotalCharges/MonetaryValue",
|
10
|
+
# :name => "Service",
|
11
|
+
:code => "Service/Code"
|
12
|
+
}) {|instance| instance.carrier = "UPS" }
|
13
|
+
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require File.dirname(__FILE__) + "/environment"
|
4
|
+
|
5
|
+
$TESTING = true
|
6
|
+
$DEBUG = true
|
7
|
+
describe "Shipping" do
|
8
|
+
if ENV['DO_IT_LIVE'] # http://www.youtube.com/watch?v=2tJjNVVwRCY&feature=related
|
9
|
+
describe "UPS" do
|
10
|
+
it "should work" do
|
11
|
+
rates = UPSRateRequest.new(
|
12
|
+
:zip => "98125",
|
13
|
+
:country => "US",
|
14
|
+
:weight => "5.00",
|
15
|
+
|
16
|
+
# optional
|
17
|
+
# :city => "Seattle",
|
18
|
+
# :state => "WA",
|
19
|
+
:request_type => "Shop" # take out shop, and it'll return one ground rate
|
20
|
+
).do
|
21
|
+
|
22
|
+
rates.should_not be_nil
|
23
|
+
rates.size.should > 1 # comment unless request_type => 'Shop'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/environment"
|
2
|
+
|
3
|
+
# === Vendor API Docs
|
4
|
+
#
|
5
|
+
# http://www.ups.com/gec/techdocs/pdf/dtk_RateXML_V1.zip
|
6
|
+
class UPSRateRequest < Consumer::Request
|
7
|
+
response_class "Rate"
|
8
|
+
error_paths({
|
9
|
+
:root => "//Error",
|
10
|
+
:code => "//ErrorCode",
|
11
|
+
:message => "//ErrorDescription"
|
12
|
+
})
|
13
|
+
yaml_defaults "shipping.yml", "ups"
|
14
|
+
required(
|
15
|
+
# these are in shipping.yml
|
16
|
+
:access_license_number,
|
17
|
+
:sender_zip,
|
18
|
+
:sender_country,
|
19
|
+
# these must be passed in
|
20
|
+
:zip,
|
21
|
+
:country,
|
22
|
+
# :city,
|
23
|
+
# :state,
|
24
|
+
:weight
|
25
|
+
)
|
26
|
+
defaults({
|
27
|
+
:customer_type => "wholesale",
|
28
|
+
:pickup_type => "daily_pickup",
|
29
|
+
:request_type => "Rate", # or Shop
|
30
|
+
:service_type => "ground",
|
31
|
+
:package_type => "your_packaging",
|
32
|
+
:weight_units => 'LBS', # or KGS
|
33
|
+
:measure_units => 'IN',
|
34
|
+
:measure_length => 0,
|
35
|
+
:measure_width => 0,
|
36
|
+
:measure_height => 0,
|
37
|
+
# optional, but all or none
|
38
|
+
# :currency_code => "US",
|
39
|
+
# :insured_value => 0
|
40
|
+
})
|
41
|
+
# optional
|
42
|
+
# * :city
|
43
|
+
# * :state
|
44
|
+
# * :sender_city
|
45
|
+
# * :sender_state
|
46
|
+
|
47
|
+
|
48
|
+
def url
|
49
|
+
return "https://wwwcie.ups.com/ups.app/xml/Rate" if $TESTING
|
50
|
+
|
51
|
+
"https://www.ups.com/ups.app/xml/Rate"
|
52
|
+
end
|
53
|
+
|
54
|
+
API_VERSION = "1.0001"
|
55
|
+
|
56
|
+
PackageTypes = {
|
57
|
+
"ups_envelope" => "01",
|
58
|
+
"your_packaging" => "02",
|
59
|
+
"ups_tube" => "03",
|
60
|
+
"ups_pak" => "04",
|
61
|
+
"ups_box" => "21",
|
62
|
+
"fedex_25_kg_box" => "24",
|
63
|
+
"fedex_10_kg_box" => "25"
|
64
|
+
}
|
65
|
+
|
66
|
+
ServiceTypes = {
|
67
|
+
"next_day" => "01",
|
68
|
+
"2day" => "02",
|
69
|
+
"ground" => "03",
|
70
|
+
"worldwide_express" => "07",
|
71
|
+
"worldwide_expedited" => "08",
|
72
|
+
"standard" => "11",
|
73
|
+
"3day" => "12",
|
74
|
+
"next_day_saver" => "13",
|
75
|
+
"next_day_early" => "14",
|
76
|
+
"worldwide_express_plus" => "54",
|
77
|
+
"2day_early" => "59"
|
78
|
+
}
|
79
|
+
|
80
|
+
PaymentTypes = {
|
81
|
+
'prepaid' => 'Prepaid',
|
82
|
+
'consignee' => 'Consignee',
|
83
|
+
'bill_third_party' => 'BillThirdParty',
|
84
|
+
'freight_collect' => 'FreightCollect'
|
85
|
+
}
|
86
|
+
|
87
|
+
# UPS-Specific types
|
88
|
+
|
89
|
+
PickupTypes = {
|
90
|
+
'daily_pickup' => '01',
|
91
|
+
'customer_counter' => '03',
|
92
|
+
'one_time_pickup' => '06',
|
93
|
+
'on_call' => '07',
|
94
|
+
'suggested_retail_rates' => '11',
|
95
|
+
'letter_center' => '19',
|
96
|
+
'air_service_center' => '20'
|
97
|
+
}
|
98
|
+
|
99
|
+
CustomerTypes = {
|
100
|
+
'wholesale' => '01',
|
101
|
+
'ocassional' => '02',
|
102
|
+
'retail' => '04'
|
103
|
+
}
|
104
|
+
|
105
|
+
def to_xml
|
106
|
+
b.instruct!
|
107
|
+
|
108
|
+
b.AccessRequest {
|
109
|
+
b.AccessLicenseNumber @access_license_number
|
110
|
+
b.UserId @user_id
|
111
|
+
b.Password @password
|
112
|
+
}
|
113
|
+
|
114
|
+
b.instruct!
|
115
|
+
|
116
|
+
b.RatingServiceSelectionRequest {
|
117
|
+
b.Request {
|
118
|
+
b.TransactionReference {
|
119
|
+
b.CustomerContext 'Rating and Service'
|
120
|
+
b.XpciVersion API_VERSION
|
121
|
+
}
|
122
|
+
b.RequestAction 'Rate'
|
123
|
+
b.RequestOption @request_type
|
124
|
+
}
|
125
|
+
b.CustomerClassification {
|
126
|
+
b.Code CustomerTypes[@customer_type]
|
127
|
+
}
|
128
|
+
b.PickupType {
|
129
|
+
b.Code PickupTypes[@pickup_type]
|
130
|
+
}
|
131
|
+
b.Shipment {
|
132
|
+
b.Shipper {
|
133
|
+
b.Address {
|
134
|
+
b.PostalCode @sender_zip
|
135
|
+
b.CountryCode @sender_country
|
136
|
+
b.City @sender_city
|
137
|
+
b.StateProvinceCode @sender_state
|
138
|
+
}
|
139
|
+
}
|
140
|
+
b.ShipTo {
|
141
|
+
b.Address {
|
142
|
+
b.PostalCode @zip
|
143
|
+
b.CountryCode @country
|
144
|
+
b.City @city
|
145
|
+
b.StateProvinceCode @state
|
146
|
+
}
|
147
|
+
}
|
148
|
+
b.Service {
|
149
|
+
b.Code ServiceTypes[@service_type]
|
150
|
+
}
|
151
|
+
b.Package {
|
152
|
+
b.PackagingType {
|
153
|
+
b.Code PackageTypes[@package_type]
|
154
|
+
b.Description 'Package'
|
155
|
+
}
|
156
|
+
b.Description 'Rate Shopping'
|
157
|
+
b.PackageWeight {
|
158
|
+
b.Weight @weight
|
159
|
+
b.UnitOfMeasurement {
|
160
|
+
b.Code @weight_units
|
161
|
+
}
|
162
|
+
}
|
163
|
+
b.Dimensions {
|
164
|
+
b.UnitOfMeasurement {
|
165
|
+
b.Code @measure_units
|
166
|
+
}
|
167
|
+
b.Length @measure_length
|
168
|
+
b.Width @measure_width
|
169
|
+
b.Height @measure_height
|
170
|
+
}
|
171
|
+
b.PackageServiceOptions {
|
172
|
+
b.InsuredValue {
|
173
|
+
b.CurrencyCode @currency_code
|
174
|
+
b.MonetaryValue @insured_value
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|