woahdae-consumer 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/History.txt +4 -0
  2. data/LICENSE +20 -0
  3. data/Manifest.txt +73 -0
  4. data/PostInstall.txt +8 -0
  5. data/README.rdoc +53 -0
  6. data/Rakefile +30 -0
  7. data/app_generators/consumer/USAGE +14 -0
  8. data/app_generators/consumer/consumer_generator.rb +89 -0
  9. data/app_generators/consumer/templates/LICENSE +20 -0
  10. data/app_generators/consumer/templates/README.rdoc +3 -0
  11. data/app_generators/consumer/templates/Rakefile +57 -0
  12. data/app_generators/consumer/templates/TODO +4 -0
  13. data/app_generators/consumer/templates/config/config.yml +2 -0
  14. data/app_generators/consumer/templates/config/config.yml.sample +1 -0
  15. data/app_generators/consumer/templates/lib/base.rb +6 -0
  16. data/app_generators/consumer/templates/rails/init.rb +1 -0
  17. data/app_generators/consumer/templates/script/destroy +14 -0
  18. data/app_generators/consumer/templates/script/generate +14 -0
  19. data/app_generators/consumer/templates/spec/spec_helper.rb +11 -0
  20. data/bin/consumer +17 -0
  21. data/config/website.yml.sample +2 -0
  22. data/consumer.gemspec +48 -0
  23. data/consumer_generators/request/USAGE +25 -0
  24. data/consumer_generators/request/request_generator.rb +94 -0
  25. data/consumer_generators/request/templates/lib/request.rb +55 -0
  26. data/consumer_generators/request/templates/lib/response.rb +12 -0
  27. data/consumer_generators/request/templates/spec/request_spec.rb +27 -0
  28. data/consumer_generators/request/templates/spec/response_spec.rb +10 -0
  29. data/consumer_generators/request/templates/spec/xml/response.xml +0 -0
  30. data/examples/active_record/README.txt +1 -0
  31. data/examples/active_record/ar_spec.rb +33 -0
  32. data/examples/active_record/database.sqlite +0 -0
  33. data/examples/active_record/environment.rb +15 -0
  34. data/examples/active_record/migration.rb +21 -0
  35. data/examples/active_record/models/book.rb +13 -0
  36. data/examples/active_record/models/contributor.rb +12 -0
  37. data/examples/active_record/xml/book.xml +6 -0
  38. data/examples/active_record/xml/book_with_contributors.xml +11 -0
  39. data/examples/active_record/xml/contributor.xml +3 -0
  40. data/examples/active_record/xml/contributor_with_books.xml +19 -0
  41. data/examples/shipping/environment.rb +3 -0
  42. data/examples/shipping/rate.rb +15 -0
  43. data/examples/shipping/shipping.yml.sample +8 -0
  44. data/examples/shipping/shipping_spec.rb +27 -0
  45. data/examples/shipping/ups_rate_request.rb +182 -0
  46. data/examples/shipping/ups_rate_response.xml +340 -0
  47. data/lib/consumer/helper.rb +111 -0
  48. data/lib/consumer/mapping.rb +184 -0
  49. data/lib/consumer/request.rb +280 -0
  50. data/lib/consumer.rb +28 -0
  51. data/script/console +10 -0
  52. data/script/destroy +14 -0
  53. data/script/generate +14 -0
  54. data/script/txt2html +71 -0
  55. data/spec/helper_spec.rb +136 -0
  56. data/spec/mapping_spec.rb +94 -0
  57. data/spec/request_spec.rb +75 -0
  58. data/spec/spec.opts +1 -0
  59. data/spec/spec_helper.rb +12 -0
  60. data/spec/xml/rate_response.xml +14 -0
  61. data/spec/xml/rate_response_error.xml +35 -0
  62. data/tasks/rspec.rake +21 -0
  63. data/test/test_consumer_generator.rb +68 -0
  64. data/test/test_generator_helper.rb +29 -0
  65. data/website/index.html +11 -0
  66. data/website/index.txt +81 -0
  67. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  68. data/website/stylesheets/screen.css +159 -0
  69. data/website/template.html.erb +50 -0
  70. 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
@@ -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
@@ -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,6 @@
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
+ </book>
6
+ </BookResponse>
@@ -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,3 @@
1
+ <ContributorResponse>
2
+ <contributor role="author"><name>David Thomas</name></contributor>
3
+ </ContributorResponse>
@@ -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,3 @@
1
+ require '../../lib/consumer'
2
+ require "ups_rate_request"
3
+ require 'rate'
@@ -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,8 @@
1
+ ups:
2
+ access_license_number: 1A2B33G45CC98765
3
+ user_id: upsuser
4
+ password: upspass
5
+ sender_zip: "98115"
6
+ sender_country: US
7
+ sender_city: Seattle
8
+ sender_state: WA
@@ -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