jordi-xml_struct 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -4,13 +4,12 @@
4
4
 
5
5
  XML Struct attempts to make accessing small, well-formed XML structures
6
6
  convenient, by using dot notation (`foo.bar`) to represent both attributes
7
- and child elements whenever possible, as well as by converting string values
8
- onto native objects (`Fixnum`, `Float`, etc).
7
+ and child elements whenever possible.
9
8
 
10
9
  XML parsing libraries (in general) have interfaces that are useful when
11
10
  one is using XML for its intended purpose, but cumbersome when one always
12
11
  sends the same XML structure, and always process all of it in the same
13
- way. This one is a bit different.
12
+ way. This one aims to be a bit different.
14
13
 
15
14
  ## Example usage
16
15
 
@@ -35,10 +34,10 @@ way. This one is a bit different.
35
34
  recipe = XMLStruct.new io_with_recipe_xml_shown_above
36
35
 
37
36
  recipe.name => "bread"
38
- recipe.title == "Basic bread" => true
37
+ recipe.title => "Basic bread"
39
38
 
40
39
  recipe.ingredients.is_a?(Array) => true
41
- recipe.ingredients.first.amount => 8
40
+ recipe.ingredients.first.amount => "8" # Not a Fixnum. Too hard. :(
42
41
 
43
42
  recipe.instructions.easy? => true
44
43
 
@@ -101,9 +100,9 @@ level. For example:
101
100
  With the same file from the `Collection auto-folding` section above, you
102
101
  also get this (courtesy of `ActiveSupport`'s `Inflector`):
103
102
 
104
- student.courses == student.course => true
103
+ student.courses.first == student.course.first => true
105
104
 
106
- ### Collection proxy:
105
+ ### Collection proxy
107
106
 
108
107
  Sometimes, collections are expressed with a container element in XML:
109
108
 
@@ -121,25 +120,10 @@ all methods it doesn't contain to the collection below, so you get:
121
120
 
122
121
  student.courses.collect { |c| c.downcase.to_sym } => [:math, :biology]
123
122
 
124
- ### Attribute auto "type-casting"
123
+ ### Question mark notation
125
124
 
126
- Attribute strings that look like integers are promoted via `to_i`, and
127
- similarly floats via `to_f`. Strings that look like booleans are also
128
- promoted, but only if called by their question mark names (such as
129
- `enabled?`.)
130
-
131
- At first, elements appear to do the same, but they don't, really. (I'd like
132
- to, but one can't define methods on, say `5`, or `-1.2`.) So in the case of
133
- the following XML:
134
-
135
- <thing><name>Foo</name></thing>
136
-
137
- While `thing.name == 'Foo'` is `true`, `thing.name => <XMLStruct ...>`. The
138
- consequence is that you can call `String` methods on `thing.name` (such as
139
- `upcase`, or `==`), but if you assign it to a new variable, you will not get
140
- a `String` object. To do that, call `thing.name.to_obj`, which will return
141
- you the auto type-casted (see above) version of `thing.name`, in this case
142
- `"Foo"`.
125
+ Strings that look like booleans are "booleanized" if called by their
126
+ question mark names (such as `enabled?`)
143
127
 
144
128
  ### Slow
145
129
 
data/TODO CHANGED
@@ -1,4 +1,3 @@
1
1
  * Make use of libxml if it's available, then fallback to REXML
2
2
  * Refactor so as to not do things recursively
3
- * Detect more types, such as dates and timestamps
4
3
  * Remove ActiveSupport dependency
data/WHATSNEW CHANGED
@@ -1,3 +1,13 @@
1
+ * 0.2.0 (2008-10-13):
2
+ - Broke backwards compatibility
3
+ - XMLRecord.new now returns decorated String or Array objects, so that
4
+ access to elements, attributes, and "collection" values is consistent
5
+ - While Strings are no longer auto-typecast to float or int, they now
6
+ have, whenever possible, a question-mark form, which attemps to
7
+ returns booleans for strings like "Yes" and "false"
8
+ - XMLRecord.new can now take a filename or a file object
9
+ - Added more tests
10
+
1
11
  * 0.1.3 (2008-10-10):
2
12
  - Switched tests to use test/spec
3
13
  - Added XMLStruct#to_obj to return the corresponding Ruby object value
data/lib/xml_struct.rb CHANGED
@@ -2,156 +2,94 @@ require 'rubygems'
2
2
  require 'activesupport'
3
3
  require 'rexml/document'
4
4
 
5
- class XMLStruct
5
+ module XMLStruct; end
6
6
 
7
- include Comparable
7
+ require File.join(File.dirname(__FILE__), 'xml_struct', 'blankish_slate')
8
+ require File.join(File.dirname(__FILE__), 'xml_struct', 'collection_proxy')
9
+ require File.join(File.dirname(__FILE__), 'xml_struct', 'string')
10
+ require File.join(File.dirname(__FILE__), 'xml_struct', 'common_behaviours')
8
11
 
9
- # Returns an XMLStruct object
12
+ module XMLStruct
13
+
14
+ # Returns a String or Array object representing the given XML, decorated
15
+ # with methods to access attributes and/or child elements.
10
16
  def self.new(duck)
11
- duck.is_a?(REXML::Element) ? super : new(REXML::Document.new(duck).root)
17
+ case duck
18
+ when ::String : return new(File.open(duck))
19
+ when ::IO : return new(REXML::Document.new(duck).root)
20
+ when REXML::Element : return new_decorated_obj(duck)
21
+ when REXML::Elements : return duck.map { |dee| new_decorated_obj(dee) }
22
+ else raise "Don't know how to start from '#{duck.class}' object."
23
+ end
12
24
  end
13
25
 
14
26
  # Takes any REXML::Element object, and converts it recursively into
15
- # the corresponding tree of XMLStruct objects
16
- def initialize(raw)
17
- @attributes, @children, @raw = {}, {}, raw
18
- @value = __get_value_from_raw_element @raw
19
-
20
- @raw.each_element { |el| __set_child el.name, self.class.new(el) }
21
- @raw.attributes.each { |n, v| __set_attribute n, v }
22
- end
23
-
24
- # Returns the raw REXML::Element object used to build this XMLStruct
25
- def to_raw_xml
26
- @raw
27
- end
28
-
29
- # Returns the Ruby value to which we pass missing methods
30
- def to_obj
31
- @value
32
- end
33
-
34
- # An XMLStruct is blank when it has a blank value, no child elements,
35
- # and no attributes. For example:
36
- #
37
- # <blank_element></blank_element>
38
- def blank?
39
- to_obj.blank? && @children.blank? && @attributes.blank?
40
- end
41
-
42
- # XMLStruct objects are compared according to their values
43
- def <=>(other)
44
- to_obj <=> other
45
- end
46
-
47
- # Array-notation access to elements and attributes. It comes handy when
48
- # the element or attribute you need to reach is not reachable via dot
49
- # notation (because it's not a valid method name, or because the method
50
- # exists, such as 'id' or 'class').
51
- #
52
- # It also supports hash keys, which are useful to reach attributes named
53
- # the same as elements in the same level (which are otherwise prioritized)
54
- #
55
- # All of this is a lot easier to exampling by example:
56
- #
57
- # <article id="main_article" author="j-random">
58
- # <author>J. Random Hacker</author>
59
- # </article>
60
- #
61
- # article.id => 9314390 # Object#id gets called
62
- # article[:id] => "main_article" # id attribute
63
- # article[:author] => <XMLStruct ...> # <author> element
64
- # article[:attr => 'author'] => "j-random" # author attribute
65
- #
66
- # Valid keys for the hash notation in the example above are :attr,
67
- # :attribute, :child, and :element.
68
- def [](name)
69
- unless name.is_a? Hash
70
- return @children[name.to_sym] if @children[name.to_sym]
71
- return @attributes[name.to_sym] if @attributes[name.to_sym]
72
- end
73
-
74
- raise 'one and only one key allowed' if name.size != 1
27
+ # the corresponding tree of decorated objects.
28
+ def self.new_decorated_obj(xml)
29
+ obj = if xml.text.blank? &&
30
+ xml.elements.map { |e| e.name }.uniq.size == 1
75
31
 
76
- case (param = name.keys.first.to_sym)
77
- when :element : @children[name.values.first.to_sym]
78
- when :child : @children[name.values.first.to_sym]
79
- when :attr : @attributes[name.values.first.to_sym]
80
- when :attribute : @attributes[name.values.first.to_sym]
81
- else raise %{ Invalid key :#{param.to_s}.
82
- Use one of :element, :child, :attr, or :attribute }.squish!
32
+ CollectionProxy.new new(xml.elements)
33
+ else
34
+ case
35
+ when (not xml.text.blank?) : xml.text.to_s
36
+ when (xml.cdatas.size >= 1) : xml.cdatas.first.to_s
37
+ else ''
38
+ end.extend String
83
39
  end
84
- end
85
-
86
- def method_missing(method, *args, &block) # :nodoc:
87
-
88
- if method.to_s.match(/\?$/) && args.empty? && block.nil?
89
- boolish = send(method.to_s.chomp('?').to_sym).to_s
90
40
 
91
- %w[ true yes t y ].include? boolish.downcase
41
+ obj.instance_variable_set :@__raw_xml, xml
92
42
 
93
- elsif to_obj.blank? && (@children.size == 1) &&
94
- (single_child = @children.values.first).respond_to?(method)
95
-
96
- single_child.send method, *args, &block
97
- else
98
- to_obj.send method, *args, &block
99
- end
100
- end
43
+ xml.each_element { |child| add_child(obj, child.name, new(child)) }
44
+ xml.attributes.each { |name, value| add_attribute(obj, name, value) }
101
45
 
102
- def inspect # :nodoc:
103
- %{ #<#{self.class.to_s} value=#{to_obj.inspect} (#{to_obj.class.to_s})
104
- attributes=[#{@attributes.keys.map(&:to_s).join(', ') }]
105
- children=[#{@children.keys.map(&:to_s).join(', ') }]> }.squish
46
+ obj.extend CommonBehaviours
106
47
  end
107
48
 
108
- private
49
+ private ##################################################################
109
50
 
110
- def __set_child(name, element) # :nodoc:
111
- key = name.to_sym
51
+ # Decorates the given object 'obj' with a method 'name' that returns the
52
+ # given 'element'. If 'name' is already taken, takes care of the array
53
+ # folding behaviour.
54
+ def self.add_child(obj, name, element)
55
+ key = name.to_sym
56
+ children = obj.instance_variable_get :@__children
112
57
 
113
- @children[key] = if @children[key]
58
+ children[key] = if children[key]
114
59
 
115
- unless respond_to?((plural_key = key.to_s.pluralize).to_sym)
116
- instance_eval %{ def #{plural_key}; @children[:#{key.to_s}]; end }
60
+ unless obj.respond_to?((plural_key = key.to_s.pluralize).to_sym)
61
+ obj.instance_eval %{
62
+ def #{plural_key}; @__children[:#{key.to_s}]; end }
117
63
  end
118
64
 
119
- @children[key] = [ @children[key] ] unless @children[key].is_a? Array
120
- @children[key] << element
65
+ children[key] = [ children[key] ] unless children[key].is_a? Array
66
+ children[key] << element
121
67
  else
122
- unless respond_to? key
123
- instance_eval %{ def #{key.to_s}; @children[:#{key.to_s}]; end }
68
+ unless obj.respond_to? key
69
+ obj.instance_eval %{
70
+ def #{key.to_s}; @__children[:#{key.to_s}]; end }
124
71
  end
125
72
 
126
73
  element
127
74
  end
128
- end
129
75
 
130
- def __set_attribute(name, attribute) # :nodoc:
131
- obj = __get_object_from_string(attribute)
132
- @attributes[(key = name.to_sym)] = obj.is_a?(String) ? obj.squish : obj
133
-
134
- unless respond_to? key
135
- instance_eval %{ def #{key.to_s}; @attributes[:#{key.to_s}]; end }
136
- end
76
+ obj.instance_variable_set :@__children, children
77
+ element
137
78
  end
138
79
 
139
- def __get_value_from_raw_element(raw) # :nodoc:
140
- str = case
141
- when raw.has_text? && !raw.text.blank? : raw.text
142
- else (raw.cdatas.first.to_s rescue '')
143
- end
80
+ # Decorates the given object 'obj' with a method 'name' that returns the
81
+ # given 'attr_value'.
82
+ def self.add_attribute(obj, name, attr_value) # :nodoc:
144
83
 
145
- __get_object_from_string str
146
- end
84
+ attributes = obj.instance_variable_get :@__attributes
85
+ attributes[(key = name.to_sym)] = attr_value.squish.extend String
147
86
 
148
- def __get_object_from_string(str) # :nodoc:
149
- case
150
- when str.blank? : nil
151
- when str.match(/[a-zA-Z]/) : str
152
- when str.match(/^[+-]?\d+$/) : str.to_i
153
- when str.match(/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/) : str.to_f
154
- else str
87
+ unless obj.respond_to? key
88
+ obj.instance_eval %{
89
+ def #{key.to_s}; @__attributes[:#{key.to_s}]; end }
155
90
  end
91
+
92
+ obj.instance_variable_set :@__attributes, attributes
93
+ attr_value
156
94
  end
157
95
  end
@@ -0,0 +1,9 @@
1
+ class XMLStruct::BlankishSlate
2
+
3
+ instance_methods.each do |m|
4
+ undef_method m unless m =~ /^__/ ||
5
+ m == 'respond_to?' ||
6
+ m == 'extend' ||
7
+ m =~ /^instance_/
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class XMLStruct::CollectionProxy < XMLStruct::BlankishSlate
2
+ def initialize(target)
3
+ @__children, @__attributes, @__target = {}, {}, target
4
+ end
5
+
6
+ def method_missing(m, *a, &b) # :nodoc:
7
+ answer = __question_answer(m, *a, &b)
8
+ answer.nil? ? (@__target.__send__(m, *a, &b) if @__target) : answer
9
+ end
10
+ end
@@ -0,0 +1,53 @@
1
+ module XMLStruct::CommonBehaviours
2
+
3
+ # Detect an existing method being called in question form:
4
+ def __question_answer(method, *args, &block)
5
+ if method.to_s.match(/\?$/) && args.empty? && block.nil?
6
+ boolish = __send__(method.to_s.chomp('?').to_sym).to_s
7
+
8
+ return true if %w[ true yes t y ].include? boolish.downcase
9
+ return false if %w[ false no f n ].include? boolish.downcase
10
+ end
11
+ end
12
+
13
+ # Array-notation access to elements and attributes. It comes handy when
14
+ # the element or attribute you need to reach is not reachable via dot
15
+ # notation (because it's not a valid method name, or because the method
16
+ # exists, such as 'id' or 'class').
17
+ #
18
+ # It also supports hash keys, which are useful to reach attributes named
19
+ # the same as elements in the same level (which otherwise go first)
20
+ #
21
+ # All of this is a lot easier to exampling by example:
22
+ #
23
+ # <article id="main_article" author="j-random">
24
+ # <author>J. Random Hacker</author>
25
+ # </article>
26
+ #
27
+ # article.id => 9314390 # Object#id gets called
28
+ # article[:id] => "main_article" # id attribute
29
+ # article[:author] => <XMLStruct ...> # <author> element
30
+ # article[:attr => 'author'] => "j-random" # author attribute
31
+ #
32
+ # Valid keys for the hash notation in the example above are :attr,
33
+ # :attribute, :child, and :element.
34
+ def [](name)
35
+ return @__target[name] if @__target && name.is_a?(Numeric)
36
+
37
+ unless name.is_a? Hash
38
+ return @__children[name.to_sym] if @__children[name.to_sym]
39
+ return @__attributes[name.to_sym] if @__attributes[name.to_sym]
40
+ end
41
+
42
+ raise 'one and only one key allowed' if name.size != 1
43
+
44
+ case (param = name.keys.first.to_sym)
45
+ when :element : @__children[name.values.first.to_sym]
46
+ when :child : @__children[name.values.first.to_sym]
47
+ when :attr : @__attributes[name.values.first.to_sym]
48
+ when :attribute : @__attributes[name.values.first.to_sym]
49
+ else raise %{ Invalid key :#{param.to_s}.
50
+ Use one of :element, :child, :attr, or :attribute }.squish!
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ module XMLStruct::String
2
+ def self.extended(obj) # :nodoc:
3
+ obj.instance_variable_set :@__children, {}
4
+ obj.instance_variable_set :@__attributes, {}
5
+ obj
6
+ end
7
+
8
+ # Attempts to detect wether this String is really an integer or float,
9
+ # and returns accordingly. If not, just returns the string.
10
+ def rb
11
+ @__rb ||= case
12
+ when (self !~ /\S/) : nil
13
+ when match(/[a-zA-Z]/) : ::String.new(self)
14
+ when match(/^[+-]?\d+$/) : self.to_i
15
+ when match(/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/) : self.to_f
16
+ else ::String.new(self)
17
+ end
18
+ end
19
+
20
+ # A decorated String is blank when it has a blank value, no child
21
+ # elements, and no attributes. For example:
22
+ #
23
+ # <blank_element></blank_element>
24
+ def blank?
25
+ (self !~ /\S/) && @__children.blank? && @__attributes.blank?
26
+ end
27
+
28
+ def method_missing(m, *a, &b) # :nodoc:
29
+ __question_answer(m, *a, &b)
30
+ end
31
+ end
@@ -5,7 +5,7 @@
5
5
 
6
6
  <!-- unambiguous element/attribute access test -->
7
7
  <sed do="eiusmod attributus">
8
- <do>eiusmod elementus</do>
8
+ <do price="$8">eiusmod elementus</do>
9
9
  </sed>
10
10
 
11
11
  <!-- Blank test -->
@@ -0,0 +1,16 @@
1
+ <recipe name="bread" prep_time="5 mins" cook_time="3 hours">
2
+ <title>Basic bread</title>
3
+ <ingredient amount="8" unit="dL">Flour</ingredient>
4
+ <ingredient amount="10" unit="grams">Yeast</ingredient>
5
+ <ingredient amount="4" unit="dL" state="warm">Water</ingredient>
6
+ <ingredient amount="1" unit="teaspoon">Salt</ingredient>
7
+ <instructions easy="yes" hard="false">
8
+ <step>Mix all ingredients together.</step>
9
+ <step>Knead thoroughly.</step>
10
+ <step>Cover with a cloth, and leave for one hour in warm room.</step>
11
+ <step>Knead again.</step>
12
+ <step>Place in a bread baking tin.</step>
13
+ <step>Cover with a cloth, and leave for one hour in warm room.</step>
14
+ <step>Bake in the oven at 180(degrees)C for 30 minutes.</step>
15
+ </instructions>
16
+ </recipe>
data/test/test_helper.rb CHANGED
@@ -23,7 +23,8 @@ def xml_file(name_symbol)
23
23
  end
24
24
 
25
25
  require 'digest/md5'
26
- { :lorem => '6dc88e269000db3be599fca3367e2aa5' }.each do |file_key, md5|
26
+ { :lorem => '9062c0f294383435d5b04ce6d67b6d61',
27
+ :recipe => '6087ab42049273d123d473093b04ab12' }.each do |file_key, md5|
27
28
 
28
29
  unless Digest::MD5.hexdigest(xml_file(file_key).read) == md5
29
30
  raise "Sample test file #{file_key.to_s}.xml doesn't match expected MD5"
@@ -1,5 +1,50 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
+ describe 'The XML Struct module' do
4
+
5
+ def setup
6
+ @filename = File.join(File.dirname(__FILE__), 'samples', 'recipe.xml')
7
+ @file = File.open @filename
8
+ @recipe = XMLStruct.new xml_file(:recipe)
9
+ end
10
+
11
+ it 'should know how to run "new" with a filename given' do
12
+ XMLStruct.new(@filename).name.should == @recipe.name
13
+ end
14
+
15
+ it 'should know how to run "new" with a file given' do
16
+ XMLStruct.new(@file).name.should == @recipe.name
17
+ end
18
+
19
+ it 'should raise an exception when given something else to "new"' do
20
+ should.raise(RuntimeError) { XMLStruct.new(8) }
21
+ end
22
+ end
23
+
24
+ describe 'README Recipe' do
25
+
26
+ def setup
27
+ @recipe = XMLStruct.new xml_file(:recipe)
28
+ end
29
+
30
+ it 'should have name and title as "bread" and "Basic bread"' do
31
+ @recipe.name.should == "bread"
32
+ @recipe.title.should == "Basic bread"
33
+ end
34
+
35
+ it 'should treat "recipe.ingredients" as an Array' do
36
+ @recipe.ingredients.is_a?(Array).should.be true
37
+ @recipe.ingredients.first.amount.to_i.should == 8
38
+ end
39
+
40
+ it 'should have 7 easy instructions' do
41
+ @recipe.instructions.easy?.should.be true
42
+ @recipe.instructions.steps.size.should == 7
43
+ @recipe.instructions.first.upcase.should ==
44
+ "MIX ALL INGREDIENTS TOGETHER."
45
+ end
46
+ end
47
+
3
48
  describe 'XML Struct' do
4
49
 
5
50
  include RubyProf::Test if defined? RubyProf::Test
@@ -8,18 +53,18 @@ describe 'XML Struct' do
8
53
  @lorem = XMLStruct.new xml_file(:lorem)
9
54
  end
10
55
 
11
- it 'should be an XMLStruct' do
12
- @lorem.should.be.an.instance_of XMLStruct
56
+ it 'should be an instance of XMLStruct::String' do
57
+ @lorem.should.be.an.instance_of ::String
13
58
  end
14
59
 
15
- it 'should be blank if devoid of children, attributes and value' do
60
+ it 'be blank if devoid of children, attributes and value' do
16
61
  @lorem.ipsum.should.be.blank
17
62
  end
18
63
 
19
- it 'should not be blank when value, children, or attributes are present' do
20
- @lorem.dolor.should.not.be.blank
21
- @lorem.sit.should.not.be.blank
22
- @lorem.ut.should.not.be.blank
64
+ it 'not be blank when value, children, or attributes are present' do
65
+ [ @lorem.dolor, @lorem.sit, @lorem.ut ].each do |xr|
66
+ xr.should.not.be.blank
67
+ end
23
68
  end
24
69
 
25
70
  it 'should allow access to attributes named like invalid methods' do
@@ -27,11 +72,11 @@ describe 'XML Struct' do
27
72
  end
28
73
 
29
74
  it 'should allow access to elements named like invalid methods' do
30
- 'veniam'.should == @lorem['_minim']
75
+ @lorem['_minim'].should == 'veniam'
31
76
  end
32
77
 
33
78
  it 'should provide unambiguous access to elements named like attributes' do
34
- 'eiusmod elementus'.should == @lorem.sed[:element => 'do']
79
+ @lorem.sed[:element => 'do'].should == 'eiusmod elementus'
35
80
  end
36
81
 
37
82
  it 'should provide unambiguous access to attributes named like elements' do
@@ -39,18 +84,18 @@ describe 'XML Struct' do
39
84
  end
40
85
 
41
86
  it 'should return elements first when using dot notation' do
42
- @lorem.sed[:element => 'do'].should == @lorem.sed.do
87
+ @lorem.sed.do.should == @lorem.sed[:element => 'do']
43
88
  end
44
89
 
45
- it 'should return elements first when using array notation and string key' do
90
+ it 'should return elements first when using [] with string key' do
46
91
  @lorem.sed['do'].should == @lorem.sed[:element => 'do']
47
92
  end
48
93
 
49
- it 'should return elements first when using array notation and symbol key' do
94
+ it 'should return elements first when using [] with symbol key' do
50
95
  @lorem.sed[:do].should == @lorem.sed[:element => 'do']
51
96
  end
52
97
 
53
- it 'should raise exception when unkown keys are used in hash-in-array mode' do
98
+ it 'should raise exception when unkown keys are used in [{}] mode' do
54
99
  should.raise(RuntimeError) { @lorem[:foo => 'bar'] }
55
100
  end
56
101
 
@@ -68,16 +113,21 @@ describe 'XML Struct' do
68
113
 
69
114
  it 'should convert integer-looking attribute strings to integers' do
70
115
  @lorem.consecteturs.each do |c|
71
- c['id'].is_a?(Numeric).should.be true
116
+ c['id'].rb.is_a?(Numeric).should.be true
72
117
  end
73
118
  end
74
119
 
75
120
  it 'should convert float-looking attribute strings to floats' do
76
121
  @lorem.consecteturs.each do |c|
77
- c.capacity.is_a?(Float).should.be true
122
+ c.capacity.rb.is_a?(Float).should.be true
78
123
  end
79
124
  end
80
125
 
126
+ it 'should not convert strings with more than numbers to Fixnum' do
127
+ @lorem.sed.do.price.rb.should == @lorem.sed.do.price
128
+ @lorem.sed.do.price.rb.should.not == 8
129
+ end
130
+
81
131
  it 'should convert bool-looking attribute strings to bools when asked' do
82
132
  @lorem.consecteturs.each { |c| c.enabled?.should == !!(c.enabled?) }
83
133
  end
@@ -88,31 +138,31 @@ describe 'XML Struct' do
88
138
  end
89
139
 
90
140
  it 'should pass forth methods to single array child when empty valued' do
91
- @lorem.cupidatats.slice(0).should.be @lorem.cupidatats.cupidatat.slice(0)
141
+ @lorem.cupidatats[0].should == @lorem.cupidatats.cupidatat[0]
92
142
  end
93
143
 
94
144
  it 'should not pass methods to single array child if not empty valued' do
95
- @lorem.voluptate.slice(0).should.not.be @lorem.voluptate.esse.slice(0)
145
+ should.raise(RuntimeError) { @lorem.voluptate[0] }
96
146
  end
97
147
 
98
148
  it 'should be valued as its text when text first and CDATA exist' do
99
- 'Laboris'.should == @lorem.ullamco
149
+ @lorem.ullamco.should == 'Laboris'
100
150
  end
101
151
 
102
152
  it 'should have the value of its first CDATA when multiple exist' do
103
- 'mollit'.should == @lorem.deserunt
153
+ @lorem.deserunt.should == 'mollit'
104
154
  end
105
155
 
106
156
  it 'should squish whitespace in string attribute values' do
107
- 'dolor'.should == @lorem.irure.metadata
157
+ @lorem.irure.metadata.should == 'dolor'
108
158
  end
109
159
 
110
160
  it 'should not squish whitespace in string element values' do
111
- " \n\t\t\treprehenderit ".should == @lorem.irure
161
+ @lorem.irure.should == " \n\t\t\treprehenderit "
112
162
  end
113
163
 
114
164
  it 'should not squish whitespace in CDATA values' do
115
- "\t foo\n".should == @lorem
165
+ @lorem.should == "\t foo\n"
116
166
  end
117
167
 
118
168
  it 'should have a working inspect function' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jordi-xml_struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordi Bunster
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-10-10 00:00:00 -07:00
12
+ date: 2008-10-13 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -37,8 +37,12 @@ files:
37
37
  - WHATSNEW
38
38
  - lib
39
39
  - lib/jordi-xml_struct.rb
40
+ - lib/xml_struct
41
+ - lib/xml_struct/blankish_slate.rb
42
+ - lib/xml_struct/collection_proxy.rb
43
+ - lib/xml_struct/common_behaviours.rb
44
+ - lib/xml_struct/string.rb
40
45
  - lib/xml_struct.rb
41
- - xml_struct.gemspec
42
46
  has_rdoc: true
43
47
  homepage: http://github.com/jordi/xml_struct
44
48
  post_install_message:
@@ -70,6 +74,7 @@ test_files:
70
74
  - test
71
75
  - test/samples
72
76
  - test/samples/lorem.xml
77
+ - test/samples/recipe.xml
73
78
  - test/test_helper.rb
74
79
  - test/vendor
75
80
  - test/vendor/test-spec
data/xml_struct.gemspec DELETED
@@ -1,69 +0,0 @@
1
- Gem::Specification.new do |s|
2
- s.name = 'xml_struct'
3
- s.version = '0.1.3'
4
- s.date = '2008-10-10'
5
-
6
- s.author = 'Jordi Bunster'
7
- s.email = 'jordi@bunster.org'
8
- s.homepage = 'http://github.com/jordi/xml_struct'
9
-
10
- s.add_dependency 'activesupport', '>= 2.1.1'
11
-
12
- s.summary = "The Rubyista's way to do quick XML sit-ups"
13
- s.description = %{ This is a library for reading (not writing) XML. It is
14
- particularly suited for cases where one is dealing with
15
- small documents of a known structure.
16
-
17
- It is slow and not devoid of caveats, but has a very
18
- pleasant, Ruby-like syntax. }.strip!.gsub! /\s+/, ' '
19
-
20
- s.test_files = %w[ test
21
- test/samples
22
- test/samples/lorem.xml
23
- test/test_helper.rb
24
- test/vendor
25
- test/vendor/test-spec
26
- test/vendor/test-spec/bin
27
- test/vendor/test-spec/bin/specrb
28
- test/vendor/test-spec/examples
29
- test/vendor/test-spec/examples/stack.rb
30
- test/vendor/test-spec/examples/stack_spec.rb
31
- test/vendor/test-spec/lib
32
- test/vendor/test-spec/lib/test
33
- test/vendor/test-spec/lib/test/spec
34
- test/vendor/test-spec/lib/test/spec/dox.rb
35
- test/vendor/test-spec/lib/test/spec/rdox.rb
36
- test/vendor/test-spec/lib/test/spec/should-output.rb
37
- test/vendor/test-spec/lib/test/spec/version.rb
38
- test/vendor/test-spec/lib/test/spec.rb
39
- test/vendor/test-spec/Rakefile
40
- test/vendor/test-spec/README
41
- test/vendor/test-spec/ROADMAP
42
- test/vendor/test-spec/SPECS
43
- test/vendor/test-spec/test
44
- test/vendor/test-spec/test/spec_dox.rb
45
- test/vendor/test-spec/test/spec_flexmock.rb
46
- test/vendor/test-spec/test/spec_mocha.rb
47
- test/vendor/test-spec/test/spec_nestedcontexts.rb
48
- test/vendor/test-spec/test/spec_new_style.rb
49
- test/vendor/test-spec/test/spec_should-output.rb
50
- test/vendor/test-spec/test/spec_testspec.rb
51
- test/vendor/test-spec/test/spec_testspec_order.rb
52
- test/vendor/test-spec/test/test_testunit.rb
53
- test/vendor/test-spec/TODO
54
- test/xml_struct_test.rb ]
55
-
56
- s.files = %w[ MIT-LICENSE
57
- README.markdown
58
- Rakefile
59
- TODO
60
- WHATSNEW
61
- lib
62
- lib/jordi-xml_struct.rb
63
- lib/xml_struct.rb
64
- xml_struct.gemspec ]
65
-
66
- s.has_rdoc = true
67
- s.extra_rdoc_files = %w[ README.markdown ]
68
- s.rdoc_options = %w[ --main README.markdown ]
69
- end