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.
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