representable 0.0.1.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/.gitignore +7 -0
  2. data/.gitmodules +3 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +3 -0
  5. data/History.txt +354 -0
  6. data/LICENSE +20 -0
  7. data/README.rdoc +186 -0
  8. data/Rakefile +10 -0
  9. data/TODO +37 -0
  10. data/VERSION +1 -0
  11. data/examples/amazon.rb +35 -0
  12. data/examples/current_weather.rb +27 -0
  13. data/examples/dashed_elements.rb +20 -0
  14. data/examples/library.rb +40 -0
  15. data/examples/posts.rb +27 -0
  16. data/examples/rails.rb +70 -0
  17. data/examples/twitter.rb +37 -0
  18. data/examples/xml/active_record.xml +70 -0
  19. data/examples/xml/amazon.xml +133 -0
  20. data/examples/xml/current_weather.xml +89 -0
  21. data/examples/xml/dashed_elements.xml +52 -0
  22. data/examples/xml/posts.xml +23 -0
  23. data/examples/xml/twitter.xml +422 -0
  24. data/lib/representable.rb +257 -0
  25. data/lib/representable/definition.rb +109 -0
  26. data/lib/representable/nokogiri_extensions.rb +19 -0
  27. data/lib/representable/references.rb +153 -0
  28. data/lib/representable/version.rb +3 -0
  29. data/lib/representable/xml.rb +79 -0
  30. data/representable.gemspec +29 -0
  31. data/spec/definition_spec.rb +495 -0
  32. data/spec/examples/active_record_spec.rb +41 -0
  33. data/spec/examples/amazon_spec.rb +54 -0
  34. data/spec/examples/current_weather_spec.rb +37 -0
  35. data/spec/examples/dashed_elements_spec.rb +20 -0
  36. data/spec/examples/library_spec.rb +46 -0
  37. data/spec/examples/post_spec.rb +24 -0
  38. data/spec/examples/twitter_spec.rb +32 -0
  39. data/spec/roxml_integration_test.rb +289 -0
  40. data/spec/roxml_spec.rb +372 -0
  41. data/spec/shared_specs.rb +15 -0
  42. data/spec/spec_helper.rb +5 -0
  43. data/spec/support/libxml.rb +3 -0
  44. data/spec/support/nokogiri.rb +3 -0
  45. data/spec/xml/array_spec.rb +36 -0
  46. data/spec/xml/attributes_spec.rb +71 -0
  47. data/spec/xml/encoding_spec.rb +53 -0
  48. data/spec/xml/namespace_spec.rb +270 -0
  49. data/spec/xml/namespaces_spec.rb +67 -0
  50. data/spec/xml/object_spec.rb +82 -0
  51. data/spec/xml/parser_spec.rb +21 -0
  52. data/spec/xml/text_spec.rb +71 -0
  53. data/test/fixtures/book_malformed.xml +5 -0
  54. data/test/fixtures/book_pair.xml +8 -0
  55. data/test/fixtures/book_text_with_attribute.xml +5 -0
  56. data/test/fixtures/book_valid.xml +5 -0
  57. data/test/fixtures/book_with_authors.xml +7 -0
  58. data/test/fixtures/book_with_contributions.xml +9 -0
  59. data/test/fixtures/book_with_contributors.xml +7 -0
  60. data/test/fixtures/book_with_contributors_attrs.xml +7 -0
  61. data/test/fixtures/book_with_default_namespace.xml +9 -0
  62. data/test/fixtures/book_with_depth.xml +6 -0
  63. data/test/fixtures/book_with_octal_pages.xml +4 -0
  64. data/test/fixtures/book_with_publisher.xml +7 -0
  65. data/test/fixtures/book_with_wrapped_attr.xml +3 -0
  66. data/test/fixtures/dictionary_of_attr_name_clashes.xml +8 -0
  67. data/test/fixtures/dictionary_of_attrs.xml +6 -0
  68. data/test/fixtures/dictionary_of_guarded_names.xml +6 -0
  69. data/test/fixtures/dictionary_of_mixeds.xml +4 -0
  70. data/test/fixtures/dictionary_of_name_clashes.xml +10 -0
  71. data/test/fixtures/dictionary_of_names.xml +4 -0
  72. data/test/fixtures/dictionary_of_texts.xml +10 -0
  73. data/test/fixtures/library.xml +30 -0
  74. data/test/fixtures/library_uppercase.xml +30 -0
  75. data/test/fixtures/muffins.xml +3 -0
  76. data/test/fixtures/nameless_ageless_youth.xml +2 -0
  77. data/test/fixtures/node_with_attr_name_conflicts.xml +1 -0
  78. data/test/fixtures/node_with_name_conflicts.xml +4 -0
  79. data/test/fixtures/numerology.xml +4 -0
  80. data/test/fixtures/person.xml +1 -0
  81. data/test/fixtures/person_with_guarded_mothers.xml +13 -0
  82. data/test/fixtures/person_with_mothers.xml +10 -0
  83. data/test/mocks/dictionaries.rb +57 -0
  84. data/test/mocks/mocks.rb +279 -0
  85. data/test/roxml_test.rb +58 -0
  86. data/test/support/fixtures.rb +11 -0
  87. data/test/test_helper.rb +6 -0
  88. data/test/unit/definition_test.rb +235 -0
  89. data/test/unit/deprecations_test.rb +24 -0
  90. data/test/unit/to_xml_test.rb +81 -0
  91. data/test/unit/xml_attribute_test.rb +39 -0
  92. data/test/unit/xml_block_test.rb +81 -0
  93. data/test/unit/xml_bool_test.rb +122 -0
  94. data/test/unit/xml_convention_test.rb +150 -0
  95. data/test/unit/xml_hash_test.rb +115 -0
  96. data/test/unit/xml_initialize_test.rb +49 -0
  97. data/test/unit/xml_name_test.rb +141 -0
  98. data/test/unit/xml_namespace_test.rb +31 -0
  99. data/test/unit/xml_object_test.rb +206 -0
  100. data/test/unit/xml_required_test.rb +94 -0
  101. data/test/unit/xml_text_test.rb +71 -0
  102. data/website/index.html +98 -0
  103. metadata +248 -0
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |test|
7
+ test.libs << 'test'
8
+ test.test_files = FileList['test/*_test.rb']
9
+ test.verbose = true
10
+ end
data/TODO ADDED
@@ -0,0 +1,37 @@
1
+ Planned:
2
+
3
+ v 3.2
4
+
5
+ * Support outputting namespaced attrs
6
+
7
+ * Consider class_inheritable_attribute rather than superclass.try stuff.
8
+
9
+ * Do some benchmarking
10
+
11
+ * Back with http://xml-object.rubyforge.org/doc/ to minimize need for specifications?
12
+
13
+ * Commandeer #parse to use opposite #from_xml, but in an unrooted, collection-friendly fashion,
14
+ ala HappyMapper's parse
15
+
16
+ v 3.x
17
+
18
+ * :self => true for sending method_missing to this attribute?
19
+
20
+ * :attributes extensions ala HappyMapper?
21
+
22
+ * Add xml_attrs helper to share :in declarations between several attributes. E.g.:
23
+
24
+ xml_reader :count, :in => 'Attributes', :as => Integer
25
+ xml_reader :something_else, :in => 'Attributes', :as => Date
26
+
27
+ becomes:
28
+
29
+ xml_attrs :in => 'Attributes' do |xml|
30
+ xml.reader :count, :as => Integer
31
+ xml.reader :something_else, :as => Date
32
+ end
33
+
34
+ * Ensure (perhaps optionally) that references are unambiguous. That is error/warn
35
+ a singular specification has multiple possible node references
36
+
37
+ * Use lazy evaluation to minimize parsing time for large files
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 3.1.6
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative './../spec/spec_helper'
3
+
4
+ # The document `pita.xml` contains both a default namespace and the 'georss'
5
+ # namespace (for the 'point' xml_reader).
6
+ module PITA
7
+ class Base
8
+ include ROXML
9
+ xml_convention :camelcase
10
+ end
11
+
12
+ class Item < Base
13
+ xml_reader :asin, :from => 'ASIN'
14
+ xml_reader :detail_page_url, :from => 'DetailPageURL'
15
+ xml_reader :manufacturer, :in => 'ItemAttributes'
16
+ # this is the only xml_reader that exists in a different namespace, so it
17
+ # must be explicitly specified
18
+ xml_reader :point, :namespace => 'georss'
19
+ end
20
+
21
+ class ItemSearchResponse < Base
22
+ xml_reader :total_results, :as => Integer, :in => 'Items'
23
+ xml_reader :total_pages, :as => Integer, :in => 'Items'
24
+ xml_reader :items, :as => [Item]
25
+ end
26
+ end
27
+
28
+ unless defined?(Spec)
29
+ response = PITA::ItemSearchResponse.from_xml(xml_for('amazon'))
30
+ p response.total_results
31
+ p response.total_pages
32
+ response.items.each do |i|
33
+ puts i.asin, i.detail_page_url, i.manufacturer, i.point, ''
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative './../spec/spec_helper'
3
+
4
+ class Base
5
+ include ROXML
6
+ xml_convention :dasherize
7
+ xml_namespace 'aws'
8
+ end
9
+
10
+ class WeatherObservation < Base
11
+ xml_name 'ob'
12
+ xml_reader :temperature, :as => Float, :from => 'aws:temp'
13
+ xml_reader :feels_like, :as => Integer
14
+ xml_reader :current_condition #, :attributes => {:icon => String} # pending
15
+ end
16
+
17
+ class Weather < Base
18
+ xml_reader :observation, :as => WeatherObservation, :required => true
19
+ end
20
+
21
+ unless defined?(Spec)
22
+ current_weather = Weather.from_xml(xml_for('current_weather')).observation
23
+ puts "temperature: #{current_weather.temperature}"
24
+ puts "feels_like: #{current_weather.feels_like}"
25
+ puts "current_condition: #{current_weather.current_condition}"
26
+ # puts "current_condition.icon: #{current_weather.current_condition.icon}" # pending
27
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative './../spec/spec_helper'
3
+
4
+ module GitHub
5
+ class Commit
6
+ include ROXML
7
+ xml_convention :dasherize
8
+
9
+ xml_reader :url
10
+ xml_reader :tree
11
+ xml_reader :message
12
+ xml_reader :id
13
+ xml_reader :committed_date, :as => Date
14
+ end
15
+ end
16
+
17
+ unless defined?(Spec)
18
+ commit = GitHub::Commit.from_xml(xml_for('dashed_elements'))
19
+ puts commit.committed_date, commit.url, commit.id, ''
20
+ end
@@ -0,0 +1,40 @@
1
+ class Publisher
2
+ include ROXML
3
+
4
+ xml_accessor :name
5
+
6
+ def initialize(name = nil)
7
+ @name = name
8
+ end
9
+
10
+ def ==(other)
11
+ name == other.name
12
+ end
13
+
14
+ # other important functionality
15
+ end
16
+
17
+ class Novel
18
+ include ROXML
19
+
20
+ xml_accessor :isbn, :from => "@ISBN" # attribute with name 'ISBN'
21
+ xml_accessor :title
22
+ xml_accessor :description, :cdata => true # text node with cdata protection
23
+ xml_accessor :author
24
+ xml_accessor :publisher, :as => Publisher # singular object reference for illustrative purposes.
25
+
26
+ def ==(other)
27
+ self.class.roxml_attrs.map(&:accessor).all? {|attr| send(attr) == other.send(attr) }
28
+ end
29
+ end
30
+
31
+ class Library
32
+ include ROXML
33
+
34
+ xml_accessor :name, :from => "NAME", :cdata => true
35
+ xml_accessor :novels, :as => [Novel] # by default roxml searches for books for in <novel> children, then, if none are present, in ./novels/novel children
36
+
37
+ def ==(other)
38
+ name == other.name && novels == other.novels
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative './../spec/spec_helper'
3
+
4
+ class Post
5
+ include ROXML
6
+
7
+ xml_reader :href, :from => :attr
8
+ xml_reader :hash, :from => :attr
9
+ xml_reader :description, :from => :attr
10
+ xml_reader :tag, :from => :attr
11
+ xml_reader :created_at, :from => '@time'
12
+ xml_reader :others, :from => :attr, :as => Integer
13
+ xml_reader :extended, :from => :attr
14
+ end
15
+
16
+ class Posts
17
+ include ROXML
18
+
19
+ xml_reader :posts, :as => [Post]
20
+ end
21
+
22
+ unless defined?(Spec)
23
+ posts = Posts.from_xml(xml_for('posts'))
24
+ posts.posts.each do |post|
25
+ puts post.description, post.href, post.extended, ''
26
+ end
27
+ end
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative './../spec/spec_helper'
3
+ require 'sqlite3'
4
+ require 'active_record'
5
+
6
+ DB_PATH = 'spec/examples/rails.sqlite3'
7
+ ActiveRecord::Base.establish_connection(
8
+ :adapter => 'sqlite3',
9
+ :database => DB_PATH
10
+ )
11
+
12
+ class Waypoint < ActiveRecord::Base
13
+ include ROXML
14
+
15
+ belongs_to :route
16
+
17
+ xml_attr :isLeg
18
+ xml_attr :lonlatx
19
+ xml_attr :lonlaty
20
+ xml_attr :gridReference
21
+ xml_attr :ascent
22
+ xml_attr :descent
23
+ xml_attr :distance
24
+ xml_attr :bearing
25
+ xml_attr :timemins
26
+ end
27
+
28
+ class Route < ActiveRecord::Base
29
+ include ROXML
30
+
31
+ has_many :waypoints
32
+
33
+ xml_attr :title
34
+ xml_attr :totalDist
35
+ xml_attr :totalMins
36
+ xml_attr :totalHg
37
+ xml_attr :lonlatx
38
+ xml_attr :lonlaty
39
+ xml_attr :grcenter
40
+
41
+ xml_attr :waypoints, :as => [Waypoint], :in => "waypoints"
42
+ end
43
+
44
+ # do a quick pseudo migration. This should only get executed on the first run
45
+ if !Waypoint.table_exists?
46
+ ActiveRecord::Base.connection.create_table(:waypoints) do |t|
47
+ t.column :route_id, :integer
48
+ t.column :isLeg, :string
49
+ t.column :lonlatx, :string
50
+ t.column :lonlaty, :string
51
+ t.column :gridReference, :string
52
+ t.column :ascent, :string
53
+ t.column :descent, :string
54
+ t.column :distance, :string
55
+ t.column :bearing, :string
56
+ t.column :timeMins, :string
57
+ end
58
+ end
59
+
60
+ if !Route.table_exists?
61
+ ActiveRecord::Base.connection.create_table(:routes) do |t|
62
+ t.column :title, :string
63
+ t.column :totalDist, :string
64
+ t.column :totalMins, :string
65
+ t.column :totalHg, :string
66
+ t.column :lonlatx, :string
67
+ t.column :lonlaty, :string
68
+ t.column :grcenter, :string
69
+ end
70
+ end
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative './../spec/spec_helper'
3
+ require 'time'
4
+
5
+ class User
6
+ include ROXML
7
+
8
+ xml_reader :id, :as => Integer
9
+ xml_reader :name
10
+ xml_reader :screen_name
11
+ xml_reader :location
12
+ xml_reader :description
13
+ xml_reader :profile_image_url
14
+ xml_reader :url
15
+ xml_reader :protected?
16
+ xml_reader :followers_count, :as => Integer
17
+ end
18
+
19
+ class Status
20
+ include ROXML
21
+
22
+ xml_reader :id, :as => Integer
23
+ xml_reader :text
24
+ xml_reader :created_at # This defaults to :as => DateTime, due to the '_at'
25
+ xml_reader :source
26
+ xml_reader :truncated?
27
+ xml_reader :in_reply_to_status_id, :as => Integer
28
+ xml_reader :in_reply_to_user_id, :as => Integer
29
+ xml_reader :favorited?
30
+ xml_reader :user, :as => User
31
+ end
32
+
33
+ class Statuses
34
+ include ROXML
35
+
36
+ xml_reader :statuses, :as => [Status]
37
+ end
@@ -0,0 +1,70 @@
1
+ <route>
2
+ <totalDist>11185.321521477119</totalDist>
3
+ <totalHg>640</totalHg>
4
+ <totalMins>235.75000000000003</totalMins>
5
+ <lonlatx>357865</lonlatx>
6
+ <lonlaty>271635</lonlaty>
7
+ <grcenter>SH 71635 57865</grcenter>
8
+ <waypoints>
9
+ <waypoint>
10
+ <isLeg>false</isLeg>
11
+ <lonlatx>357290</lonlatx>
12
+ <lonlaty>271650</lonlaty>
13
+ <gridReference>SH 71650 57290</gridReference>
14
+ <ascent>81</ascent>
15
+ <descent>220</descent>
16
+ <distance>0</distance>
17
+ <bearing>0</bearing>
18
+ </waypoint>
19
+ <waypoint>
20
+ <isLeg>false</isLeg>
21
+ <lonlatx>357260</lonlatx>
22
+ <lonlaty>274600</lonlaty>
23
+ <gridReference>SH 74600 57260</gridReference>
24
+ <ascent>275</ascent>
25
+ <descent>48</descent>
26
+ <distance>2950.152538429157</distance>
27
+ <bearing>91</bearing>
28
+ </waypoint>
29
+ <waypoint>
30
+ <isLeg>false</isLeg>
31
+ <lonlatx>359160</lonlatx>
32
+ <lonlaty>273330</lonlaty>
33
+ <gridReference>SH 73330 59160</gridReference>
34
+ <ascent>73</ascent>
35
+ <descent>170</descent>
36
+ <distance>2285.3664913969487</distance>
37
+ <bearing>326</bearing>
38
+ </waypoint>
39
+ <waypoint>
40
+ <isLeg>false</isLeg>
41
+ <lonlatx>359170</lonlatx>
42
+ <lonlaty>270050</lonlaty>
43
+ <gridReference>SH 70050 59170</gridReference>
44
+ <ascent>182</ascent>
45
+ <descent>172</descent>
46
+ <distance>3280.015243867016</distance>
47
+ <bearing>270</bearing>
48
+ </waypoint>
49
+ <waypoint>
50
+ <isLeg>false</isLeg>
51
+ <lonlatx>357470</lonlatx>
52
+ <lonlaty>269740</lonlaty>
53
+ <gridReference>SH 69740 57470</gridReference>
54
+ <ascent>29</ascent>
55
+ <descent>107</descent>
56
+ <distance>1728.0335644888382</distance>
57
+ <bearing>190</bearing>
58
+ </waypoint>
59
+ <waypoint>
60
+ <isLeg>false</isLeg>
61
+ <lonlatx>356840</lonlatx>
62
+ <lonlaty>270440</lonlaty>
63
+ <gridReference>SH 70440 56840</gridReference>
64
+ <ascent>640</ascent>
65
+ <descent>717</descent>
66
+ <distance>941.7536832951597</distance>
67
+ <bearing>132</bearing>
68
+ </waypoint>
69
+ </waypoints>
70
+ </route>
@@ -0,0 +1,133 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05" xmlns:georss="http://www.georss.org/georss">
3
+ <OperationRequest>
4
+ <HTTPHeaders>
5
+ <Header Name="UserAgent">
6
+ </Header>
7
+ </HTTPHeaders>
8
+ <RequestId>16WRJBVEM155Q026KCV1</RequestId>
9
+ <Arguments>
10
+ <Argument Name="SearchIndex" Value="Books"></Argument>
11
+ <Argument Name="Service" Value="AWSECommerceService"></Argument>
12
+ <Argument Name="Title" Value="Ruby on Rails"></Argument>
13
+ <Argument Name="Operation" Value="ItemSearch"></Argument>
14
+ <Argument Name="AWSAccessKeyId" Value="dontbeaswoosh"></Argument>
15
+ </Arguments>
16
+ <RequestProcessingTime>0.064924955368042</RequestProcessingTime>
17
+ </OperationRequest>
18
+ <Items>
19
+ <Request>
20
+ <IsValid>True</IsValid>
21
+ <ItemSearchRequest>
22
+ <SearchIndex>Books</SearchIndex>
23
+ <Title>Ruby on Rails</Title>
24
+ </ItemSearchRequest>
25
+ </Request>
26
+ <TotalResults>22</TotalResults>
27
+ <TotalPages>3</TotalPages>
28
+ <Item>
29
+ <ASIN>0321480791</ASIN>
30
+ <georss:point>38.5351715088 -121.7948684692</georss:point>
31
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
32
+ <ItemAttributes>
33
+ <Author>Michael Hartl</Author>
34
+ <Author>Aurelius Prochazka</Author>
35
+ <Manufacturer>Addison-Wesley Professional</Manufacturer>
36
+ <ProductGroup>Book</ProductGroup>
37
+ <Title>RailsSpace: Building a Social Networking Website with Ruby on Rails (Addison-Wesley Professional Ruby Series)</Title>
38
+ </ItemAttributes>
39
+ </Item>
40
+ <Item>
41
+ <ASIN>047022388X</ASIN>
42
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=047022388X%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/047022388X%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
43
+ <ItemAttributes>
44
+ <Author>Noel Rappin</Author>
45
+ <Manufacturer>Wrox</Manufacturer>
46
+ <ProductGroup>Book</ProductGroup>
47
+ <Title>Professional Ruby on Rails</Title>
48
+ </ItemAttributes>
49
+ </Item>
50
+ <Item>
51
+ <ASIN>1590598814</ASIN>
52
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=1590598814%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/1590598814%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
53
+ <ItemAttributes>
54
+ <Author>Ola Bini</Author>
55
+ <Manufacturer>Apress</Manufacturer>
56
+ <ProductGroup>Book</ProductGroup>
57
+ <Title>Practical JRuby on Rails Web 2.0 Projects: Bringing Ruby on Rails to Java</Title>
58
+ </ItemAttributes>
59
+ </Item>
60
+ <Item>
61
+ <ASIN>0596101325</ASIN>
62
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0596101325%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0596101325%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
63
+ <ItemAttributes>
64
+ <Author>Bruce Tate</Author>
65
+ <Author>Curt Hibbs</Author>
66
+ <Manufacturer>O'Reilly Media, Inc.</Manufacturer>
67
+ <ProductGroup>Book</ProductGroup>
68
+ <Title>Ruby on Rails: Up and Running</Title>
69
+ </ItemAttributes>
70
+ </Item>
71
+ <Item>
72
+ <ASIN>0470081201</ASIN>
73
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0470081201%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0470081201%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
74
+ <ItemAttributes>
75
+ <Author>Barry Burd</Author>
76
+ <Manufacturer>For Dummies</Manufacturer>
77
+ <ProductGroup>Book</ProductGroup>
78
+ <Title>Ruby on Rails For Dummies (For Dummies (Computer/Tech))</Title>
79
+ </ItemAttributes>
80
+ </Item>
81
+ <Item>
82
+ <ASIN>0975841955</ASIN>
83
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0975841955%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0975841955%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
84
+ <ItemAttributes>
85
+ <Author>Patrick Lenz</Author>
86
+ <Manufacturer>SitePoint</Manufacturer>
87
+ <ProductGroup>Book</ProductGroup>
88
+ <Title>Build Your Own Ruby on Rails Web Applications</Title>
89
+ </ItemAttributes>
90
+ </Item>
91
+ <Item>
92
+ <ASIN>0470069155</ASIN>
93
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0470069155%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0470069155%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
94
+ <ItemAttributes>
95
+ <Author>Steve, Ph.D. Holzner</Author>
96
+ <Manufacturer>Wrox</Manufacturer>
97
+ <ProductGroup>Book</ProductGroup>
98
+ <Title>Beginning Ruby on Rails (Wrox Beginning Guides)</Title>
99
+ </ItemAttributes>
100
+ </Item>
101
+ <Item>
102
+ <ASIN>1590597362</ASIN>
103
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=1590597362%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/1590597362%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
104
+ <ItemAttributes>
105
+ <Author>Christian Hellsten</Author>
106
+ <Author>Jarkko Laine</Author>
107
+ <Manufacturer>Apress</Manufacturer>
108
+ <ProductGroup>Book</ProductGroup>
109
+ <Title>Beginning Ruby on Rails E-Commerce: From Novice to Professional (Rails)</Title>
110
+ </ItemAttributes>
111
+ </Item>
112
+ <Item>
113
+ <ASIN>1590597524</ASIN>
114
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=1590597524%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/1590597524%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
115
+ <ItemAttributes>
116
+ <Author>Justin Williams</Author>
117
+ <Manufacturer>friends of ED</Manufacturer>
118
+ <ProductGroup>Book</ProductGroup>
119
+ <Title>Rails Solutions: Ruby on Rails Made Easy (Solutions)</Title>
120
+ </ItemAttributes>
121
+ </Item>
122
+ <Item>
123
+ <ASIN>0321517067</ASIN>
124
+ <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0321517067%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321517067%253FSubscriptionId=dontbeaswoosh</DetailPageURL>
125
+ <ItemAttributes>
126
+ <Author>Aurelius Prochazka</Author>
127
+ <Manufacturer>Addison-Wesley Professional</Manufacturer>
128
+ <ProductGroup>Book</ProductGroup>
129
+ <Title>RailsSpace Ruby on Rails Tutorial (Video Training) (LiveLessons)</Title>
130
+ </ItemAttributes>
131
+ </Item>
132
+ </Items>
133
+ </ItemSearchResponse>