roxml 2.4.3 → 2.5.0

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 (47) hide show
  1. data/History.txt +54 -0
  2. data/Manifest.txt +9 -6
  3. data/README.rdoc +24 -17
  4. data/Rakefile +2 -1
  5. data/TODO +30 -31
  6. data/examples/active_record.rb +69 -0
  7. data/examples/amazon.rb +1 -1
  8. data/examples/current_weather.rb +1 -1
  9. data/examples/posts.rb +8 -8
  10. data/examples/twitter.rb +2 -2
  11. data/examples/xml/active_record.xml +70 -0
  12. data/lib/roxml.rb +174 -174
  13. data/lib/roxml/definition.rb +165 -89
  14. data/lib/roxml/extensions/deprecation.rb +5 -0
  15. data/lib/roxml/extensions/string/conversions.rb +2 -3
  16. data/lib/roxml/hash_definition.rb +26 -25
  17. data/lib/roxml/xml.rb +15 -6
  18. data/lib/roxml/xml/parsers/libxml.rb +9 -6
  19. data/lib/roxml/xml/parsers/rexml.rb +1 -1
  20. data/lib/roxml/xml/references.rb +14 -17
  21. data/roxml.gemspec +8 -5
  22. data/spec/definition_spec.rb +563 -0
  23. data/spec/examples/active_record_spec.rb +43 -0
  24. data/spec/roxml_spec.rb +372 -0
  25. data/spec/shared_specs.rb +15 -0
  26. data/spec/spec_helper.rb +21 -4
  27. data/spec/string_spec.rb +15 -0
  28. data/spec/xml/parser_spec.rb +22 -0
  29. data/test/fixtures/book_valid.xml +1 -1
  30. data/test/fixtures/person_with_guarded_mothers.xml +3 -3
  31. data/test/mocks/mocks.rb +57 -45
  32. data/test/unit/definition_test.rb +161 -12
  33. data/test/unit/deprecations_test.rb +97 -0
  34. data/test/unit/to_xml_test.rb +30 -1
  35. data/test/unit/xml_bool_test.rb +15 -3
  36. data/test/unit/xml_construct_test.rb +6 -6
  37. data/test/unit/xml_hash_test.rb +18 -0
  38. data/test/unit/xml_initialize_test.rb +6 -3
  39. data/test/unit/xml_object_test.rb +66 -5
  40. data/test/unit/xml_text_test.rb +3 -0
  41. metadata +23 -15
  42. data/test/unit/array_test.rb +0 -16
  43. data/test/unit/freeze_test.rb +0 -71
  44. data/test/unit/inheritance_test.rb +0 -63
  45. data/test/unit/overriden_output_test.rb +0 -33
  46. data/test/unit/roxml_test.rb +0 -60
  47. data/test/unit/string_test.rb +0 -11
@@ -1,3 +1,57 @@
1
+ == 2.5.0 (February 24, 2009)
2
+
3
+ * major enhancements
4
+
5
+ * support for mapping ActiveRecord classes. See examples/active_record.rb.
6
+ * .from_xml will now use the setter for the declared variable, if one is available,
7
+ rather than directly setting the instance variable
8
+ * All declaration type arguments are now supported via the :as parameter, e.g. :as => [MyType]. Other uses are deprecated.
9
+ * All xml source path arguments are now supported via the :from and :in parameters, e.g. :from => :attr or :from => '@MyAttr'. Other uses are deprecated.
10
+ * All other options are presented separately, e.g. :cdata => true rather than :as => :cdata. Other uses are deprecated.
11
+
12
+ * minor enhancements
13
+
14
+ * .xml_attr declaration declares neither a reader nor a writer. With it you're left to your own devices.
15
+ * You can use literal [] for the [:text] object type declaration,
16
+ though they should be used in the :as parameter: :as => []
17
+ * You can use [] with your :as declarations. e.g. :as => [Float] is
18
+ equivalent to the old :as => [Float, :array]
19
+ * Show the actual call point of a deprecation, rather than some internal path
20
+ * Add support for BigDecimal and Fixnum as block shorthands [James Healy]
21
+ * Update libxml support to 0.9.6, and add it as a dependency, to ensure correct versioning, and
22
+ as it's an order of magnitude faster than rexml
23
+
24
+ * breaking changes
25
+
26
+ * :else option only applies to instances created via .from_xml
27
+ * On .from_xml, #initialize is now called with the *initialization_args before extracting attributes from the xml.
28
+ * #xml_initialize has been replaced with the #after_parse callback, which takes no arguments.
29
+ * .xml_accessor will overwrite the setter for this variable if it has already been defined. Use .xml_reader or .xml_attr,
30
+ or define your writer later, if this is not the behavior you want.
31
+
32
+ * deprecations
33
+
34
+ * Use :cdata => true rather than :as => :cdata
35
+ * Use literal [] around your regular object type, rather than :as => :array
36
+ * Use :from => :content rather than the :content object declaration type
37
+ * Specifying an unknown symbol or Class for :as will raise in 3.0
38
+ * Specifying :as with anything other than a type argument e.g. :bool, Float, [Date],
39
+ will not be supported in 3.0
40
+ * Use :from => :attr or :from => '@attribute_name' rather than the :attr
41
+ object declaration type
42
+ * Passing any type declaration outside the :as parameter is deprecated
43
+ * In 3.0, attributes ending in _on and _at will default to :as => Date and DateTime, respectively,
44
+ rather than :text
45
+ * Deprecated hash :attrs declaration syntax in favor of {:key => '@attr1', :value => '@attr2'}
46
+ * Deprecated hash {Type => 'name'} declaration syntax in favor of {:as => Type, :from => 'name}
47
+ * Deprecated String#to_utf and #to_latin.
48
+
49
+ * bug fixes
50
+
51
+ * xml_accessor now properly handles punctuation, such that the writer appears without '?' for boolean attributes
52
+ * text node contents are no longer truncated when '&' are present in the contents
53
+ * When using :as => Integer or Float, don't raise on missing element [James Healy]
54
+
1
55
  == 2.4.3 (February 1, 2009)
2
56
 
3
57
  * 1 bug fix
@@ -5,11 +5,13 @@ README.rdoc
5
5
  Rakefile
6
6
  TODO
7
7
  config/website.yml
8
+ examples/active_record.rb
8
9
  examples/amazon.rb
9
10
  examples/current_weather.rb
10
11
  examples/dashed_elements.rb
11
12
  examples/posts.rb
12
13
  examples/twitter.rb
14
+ examples/xml/active_record.xml
13
15
  examples/xml/amazon.xml
14
16
  examples/xml/current_weather.xml
15
17
  examples/xml/dashed_elements.xml
@@ -31,13 +33,19 @@ lib/roxml/xml/parsers/libxml.rb
31
33
  lib/roxml/xml/parsers/rexml.rb
32
34
  lib/roxml/xml/references.rb
33
35
  roxml.gemspec
36
+ spec/definition_spec.rb
37
+ spec/examples/active_record_spec.rb
34
38
  spec/examples/amazon_spec.rb
35
39
  spec/examples/current_weather_spec.rb
36
40
  spec/examples/dashed_elements_spec.rb
37
41
  spec/examples/post_spec.rb
38
42
  spec/examples/twitter_spec.rb
43
+ spec/roxml_spec.rb
44
+ spec/shared_specs.rb
39
45
  spec/spec.opts
40
46
  spec/spec_helper.rb
47
+ spec/string_spec.rb
48
+ spec/xml/parser_spec.rb
41
49
  tasks/rspec.rake
42
50
  tasks/test.rake
43
51
  test/bugs/rexml_bugs.rb
@@ -75,13 +83,8 @@ test/mocks/dictionaries.rb
75
83
  test/mocks/mocks.rb
76
84
  test/release/dependencies_test.rb
77
85
  test/test_helper.rb
78
- test/unit/array_test.rb
79
86
  test/unit/definition_test.rb
80
- test/unit/freeze_test.rb
81
- test/unit/inheritance_test.rb
82
- test/unit/overriden_output_test.rb
83
- test/unit/roxml_test.rb
84
- test/unit/string_test.rb
87
+ test/unit/deprecations_test.rb
85
88
  test/unit/to_xml_test.rb
86
89
  test/unit/xml_attribute_test.rb
87
90
  test/unit/xml_block_test.rb
@@ -14,17 +14,17 @@ ROXML, you can annotate the Ruby classes as follows:
14
14
  class Book
15
15
  include ROXML
16
16
 
17
- xml_reader :isbn, :attr => "ISBN" # attribute with name 'ISBN'
17
+ xml_reader :isbn, :from => "@ISBN" # attribute with name 'ISBN'
18
18
  xml_reader :title
19
- xml_reader :description, :as => :cdata # text node with cdata protection
19
+ xml_reader :description, :cdata => true # text node with cdata protection
20
20
  xml_reader :author
21
21
  end
22
22
 
23
23
  class Library
24
24
  include ROXML
25
25
 
26
- xml_accessor :name, :from => "NAME", :as => :cdata
27
- xml_accessor :books, [Book], :in => "books"
26
+ xml_accessor :name, :from => "NAME", :cdata => true
27
+ xml_accessor :books, :as => [Book]
28
28
  end
29
29
 
30
30
  To create a library and put a number of books in it we could run the following code:
@@ -66,7 +66,7 @@ can be mapped using the following code:
66
66
  include ROXML
67
67
 
68
68
  xml_name :book
69
- xml_reader :publisher, Publisher
69
+ xml_reader :publisher, :as => Publisher
70
70
  end
71
71
 
72
72
  Note: In the above example, _xml_name_ annotation tells ROXML to set the element
@@ -78,34 +78,41 @@ in this case.
78
78
  Extending the above examples, say you want to parse a book's page count and have it available as an Integer.
79
79
  In such a case, you can extend any object with a block to manipulate it's value at parse time. For example:
80
80
 
81
- class Child
81
+ class Dog
82
82
  include ROXML
83
83
 
84
- xml_reader :age, :attr do |val|
85
- Integer(val)
86
- end
84
+ xml_reader(:age, :from => '@human_years', :as => Integer) {|years| years * 7 }
87
85
  end
88
86
 
89
87
  The result of the block above is stored, rather than the actual value parsed from the document.
90
88
 
91
89
  == Construction
92
90
 
93
- Complicated initialization may require action on multiple attributes of an object. As such, you can
94
- define method xml_initialize to perform initialization after instantiation and parsing, including
95
- causing your ROXML object to call its own constructor, as in the following:
91
+ Object lifecycle is as follows: .from_xml is called with option initialization_args. .new,
92
+ and thus #initialize, is called with those same args. Then the object is populated
93
+ with the attribute values from xml. Then the #after_parse callback is called, with no arguments.
94
+ In it you can ensure that your object initialization is complete, including initialization which
95
+ requires more than one variable in concert.
96
+
97
+ E.g.:
96
98
 
97
99
  class Measurement
98
100
  include ROXML
99
101
 
100
- xml_reader :units, :attr
101
- xml_reader :value, :content
102
+ xml_reader :units, :from => :attr
103
+ xml_reader :value, :from => :content
104
+
105
+ def initialize(value = 0, units = 'meters')
106
+ to_metric
107
+ end
102
108
 
103
- def xml_initialize
109
+ private
110
+ def after_parse
104
111
  # xml attributes of self are already valid
105
- initialize(value, units)
112
+ to_metric
106
113
  end
107
114
 
108
- def initialize(value, units)
115
+ def to_metric
109
116
  # translate units & value into metric, for example
110
117
  end
111
118
  end
data/Rakefile CHANGED
@@ -16,7 +16,8 @@ $hoe = Hoe.new('roxml', ROXML::VERSION) do |p|
16
16
  p.changes = File.read("History.txt").split(/^==/)[1].strip
17
17
  p.rubyforge_name = p.name
18
18
  p.extra_deps = [
19
- ['activesupport','>= 2.1.0']
19
+ ['activesupport','>= 2.1.0'],
20
+ ['libxml-ruby', '>= 0.8.6']
20
21
  ]
21
22
  p.extra_dev_deps = [
22
23
  ['newgem', ">= #{::Newgem::VERSION}"]
data/TODO CHANGED
@@ -1,37 +1,10 @@
1
1
  Planned:
2
2
 
3
- v 2.5
4
- * Test out compatibility with ActiveRecord such that it's easy
5
- to have both xml & database-sourced objects
6
-
7
- * provide an overridable extension point for the #to_xml-ing of
8
- values. This would enable easy accommodation of non-standard formats.
9
- For example, formatting a number with leading zeros.
10
-
11
- * Ensure (perhaps optionally) that references are unambiguous. That is error/warn
12
- a singular specification has multiple possible node references
13
-
14
- * Automatically use Date or DateTime for accessors ending in '_on' and '_at', respectively
15
-
16
- * Add xml_in helper to share :in declarations between several attributes. E.g.:
17
-
18
- xml_reader :count, :in => 'Attributes', :as => Integer
19
- xml_reader :something_else, :in => 'Attributes', :as => Date
20
-
21
- becomes:
22
-
23
- xml_in 'Attributes' do |xml|
24
- xml.reader :count, :as => Integer
25
- xml.reader :something_else, :as => Date
26
- end
27
-
28
- * :self => true for sending method_missing to this attribute?
29
-
30
- * :attributes extensions ala HappyMapper?
31
-
32
3
  v 3.0
33
4
  * remove deprecated functionality
34
5
 
6
+ * Automatically use Date or DateTime for accessors ending in '_on' and '_at', respectively
7
+
35
8
  * Clarify API via seperation of concerns. :as for Type, :from and :in for location,
36
9
  All other options as named options, e.g. :cdata => true rather than :as => :cdata.
37
10
  A few not so great examples...:
@@ -52,12 +25,38 @@ v 3.0
52
25
 
53
26
  xml_reader :count, :size, :number, :as => Integer, :from => :attr
54
27
 
28
+ * Consider class_inheritable_attribute rather than superclass.try stuff.
29
+
30
+ * Do some benchmarking
31
+
32
+ v 3.1
33
+
34
+ * Back with http://xml-object.rubyforge.org/doc/ to minimize need for specifications?
35
+
55
36
  * Commandeer #parse to use opposite #from_xml, but in an unrooted, collection-friendly fashion,
56
37
  ala HappyMapper's parse
57
38
 
58
- * Back with http://xml-object.rubyforge.org/doc/ to minimize need for specifications?
39
+ v 3.x
40
+
41
+ * :self => true for sending method_missing to this attribute?
42
+
43
+ * :attributes extensions ala HappyMapper?
44
+
45
+ * Add xml_attrs helper to share :in declarations between several attributes. E.g.:
46
+
47
+ xml_reader :count, :in => 'Attributes', :as => Integer
48
+ xml_reader :something_else, :in => 'Attributes', :as => Date
49
+
50
+ becomes:
51
+
52
+ xml_attrs :in => 'Attributes' do |xml|
53
+ xml.reader :count, :as => Integer
54
+ xml.reader :something_else, :as => Date
55
+ end
56
+
57
+ * Ensure (perhaps optionally) that references are unambiguous. That is error/warn
58
+ a singular specification has multiple possible node references
59
59
 
60
60
  * Use lazy evaluation to minimize parsing time for large files
61
61
 
62
- * Consider class_inheritable_attribute rather than superclass.try stuff.
63
62
 
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec/spec_helper')
3
+ require 'sqlite3'
4
+ require 'activerecord'
5
+
6
+ ActiveRecord::Base.establish_connection(
7
+ :adapter => 'sqlite3',
8
+ :database => "examples/active_record/active_record.sqlite3"
9
+ )
10
+
11
+ class Waypoint < ActiveRecord::Base
12
+ include ROXML
13
+
14
+ belongs_to :route
15
+
16
+ xml_attr :isLeg
17
+ xml_attr :lonlatx
18
+ xml_attr :lonlaty
19
+ xml_attr :gridReference
20
+ xml_attr :ascent
21
+ xml_attr :descent
22
+ xml_attr :distance
23
+ xml_attr :bearing
24
+ xml_attr :timemins
25
+ end
26
+
27
+ class Route < ActiveRecord::Base
28
+ include ROXML
29
+
30
+ has_many :waypoints
31
+
32
+ xml_attr :title
33
+ xml_attr :totalDist
34
+ xml_attr :totalMins
35
+ xml_attr :totalHg
36
+ xml_attr :lonlatx
37
+ xml_attr :lonlaty
38
+ xml_attr :grcenter
39
+
40
+ xml_attr :waypoints, :as => [Waypoint], :in => "waypoints"
41
+ end
42
+
43
+ # do a quick pseudo migration. This should only get executed on the first run
44
+ if !Waypoint.table_exists?
45
+ ActiveRecord::Base.connection.create_table(:waypoints) do |t|
46
+ t.column :route_id, :integer
47
+ t.column :isLeg, :string
48
+ t.column :lonlatx, :string
49
+ t.column :lonlaty, :string
50
+ t.column :gridReference, :string
51
+ t.column :ascent, :string
52
+ t.column :descent, :string
53
+ t.column :distance, :string
54
+ t.column :bearing, :string
55
+ t.column :timeMins, :string
56
+ end
57
+ end
58
+
59
+ if !Route.table_exists?
60
+ ActiveRecord::Base.connection.create_table(:routes) do |t|
61
+ t.column :title, :string
62
+ t.column :totalDist, :string
63
+ t.column :totalMins, :string
64
+ t.column :totalHg, :string
65
+ t.column :lonlatx, :string
66
+ t.column :lonlaty, :string
67
+ t.column :grcenter, :string
68
+ end
69
+ end
@@ -21,7 +21,7 @@ module PITA
21
21
  class ItemSearchResponse < Base
22
22
  xml_reader :total_results, :as => Integer, :in => 'Items'
23
23
  xml_reader :total_pages, :as => Integer, :in => 'Items'
24
- xml_reader :items, [Item]
24
+ xml_reader :items, :as => [Item]
25
25
  end
26
26
  end
27
27
 
@@ -15,7 +15,7 @@ class WeatherObservation < Base
15
15
  end
16
16
 
17
17
  class Weather < Base
18
- xml_reader :observation, WeatherObservation, :required => true
18
+ xml_reader :observation, :as => WeatherObservation, :required => true
19
19
  end
20
20
 
21
21
  unless defined?(Spec)
@@ -4,19 +4,19 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec/spec_helper')
4
4
  class Post
5
5
  include ROXML
6
6
 
7
- xml_reader :href, :attr
8
- xml_reader :hash, :attr
9
- xml_reader :description, :attr
10
- xml_reader :tag, :attr
11
- xml_reader :time, :attr, :as => DateTime
12
- xml_reader :others, :attr, :as => Integer
13
- xml_reader :extended, :attr
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 :time, :from => :attr, :as => DateTime
12
+ xml_reader :others, :from => :attr, :as => Integer
13
+ xml_reader :extended, :from => :attr
14
14
  end
15
15
 
16
16
  class Posts
17
17
  include ROXML
18
18
 
19
- xml_reader :posts, [Post]
19
+ xml_reader :posts, :as => [Post]
20
20
  end
21
21
 
22
22
  unless defined?(Spec)
@@ -27,11 +27,11 @@ class Status
27
27
  xml_reader :in_reply_to_status_id, :as => Integer
28
28
  xml_reader :in_reply_to_user_id, :as => Integer
29
29
  xml_reader :favorited?
30
- xml_reader :user, User
30
+ xml_reader :user, :as => User
31
31
  end
32
32
 
33
33
  class Statuses
34
34
  include ROXML
35
35
 
36
- xml_reader :statuses, [Status]
36
+ xml_reader :statuses, :as => [Status]
37
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>