eim_xml 0.0.3
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.
- data/Rakefile +23 -0
- data/Rakefile.utirake +334 -0
- data/lib/eim_xml/assertions.rb +16 -0
- data/lib/eim_xml/dsl.rb +105 -0
- data/lib/eim_xml/formatter.rb +112 -0
- data/lib/eim_xml/matcher.rb +25 -0
- data/lib/eim_xml/parser.rb +87 -0
- data/lib/eim_xml/xhtml/dsl.rb +18 -0
- data/lib/eim_xml/xhtml.rb +135 -0
- data/lib/eim_xml.rb +210 -0
- data/spec/assertions_spec.rb +29 -0
- data/spec/dsl_spec.rb +217 -0
- data/spec/eim_xml_spec.rb +441 -0
- data/spec/formatter_spec.rb +215 -0
- data/spec/parser_spec.rb +102 -0
- data/spec/xhtml_spec.rb +490 -0
- metadata +82 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
require "eim_xml"
|
2
|
+
require "eim_xml/formatter"
|
3
|
+
|
4
|
+
module EimXML::XHTML
|
5
|
+
module DocType
|
6
|
+
XHTML_MATHML = %[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd">]
|
7
|
+
end
|
8
|
+
|
9
|
+
class Base_ < EimXML::Element
|
10
|
+
end
|
11
|
+
|
12
|
+
class HTML < Base_
|
13
|
+
attr_accessor :prefix
|
14
|
+
module NameSpace
|
15
|
+
XHTML = "http://www.w3.org/1999/xhtml"
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(attributes={})
|
19
|
+
super(:html, attributes)
|
20
|
+
end
|
21
|
+
|
22
|
+
def write_to(out="")
|
23
|
+
out << @prefix << "\n" if @prefix
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Simple_ < Base_
|
29
|
+
def initialize(attributes={})
|
30
|
+
super(self.class.name[/.*::(.*)/, 1].downcase.to_sym, attributes)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class PreserveSpace_ < Simple_; end
|
35
|
+
|
36
|
+
class HEAD < Simple_; end
|
37
|
+
class META < Simple_; end
|
38
|
+
class LINK < Simple_; end
|
39
|
+
class STYLE < PreserveSpace_; end
|
40
|
+
class SCRIPT < PreserveSpace_; end
|
41
|
+
class TITLE < Simple_; end
|
42
|
+
class BODY < Simple_; end
|
43
|
+
class PRE < PreserveSpace_; end
|
44
|
+
class FORM < Simple_
|
45
|
+
def initialize(attributes={})
|
46
|
+
if attributes
|
47
|
+
if s = attributes.delete(:session)
|
48
|
+
name = attributes.delete(:session_name) || "token"
|
49
|
+
require "digest/sha1"
|
50
|
+
token = s[name] ||= Digest::SHA1.hexdigest("#{$$}#{Time.now}#{rand}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
super
|
54
|
+
add(HIDDEN.new(:name=>name, :value=>token)) if token
|
55
|
+
end
|
56
|
+
end
|
57
|
+
class H1 < PreserveSpace_; end
|
58
|
+
class H2 < PreserveSpace_; end
|
59
|
+
class H3 < PreserveSpace_; end
|
60
|
+
class H4 < PreserveSpace_; end
|
61
|
+
class H5 < PreserveSpace_; end
|
62
|
+
class H6 < PreserveSpace_; end
|
63
|
+
class P < PreserveSpace_; end
|
64
|
+
class A < PreserveSpace_; end
|
65
|
+
class EM < PreserveSpace_; end
|
66
|
+
class STRONG < PreserveSpace_; end
|
67
|
+
class DIV < Simple_; end
|
68
|
+
class SPAN < PreserveSpace_; end
|
69
|
+
class UL < Simple_; end
|
70
|
+
class OL < Simple_; end
|
71
|
+
class LI < PreserveSpace_; end
|
72
|
+
class DL < Simple_; end
|
73
|
+
class DT < PreserveSpace_; end
|
74
|
+
class DD < PreserveSpace_; end
|
75
|
+
class TABLE < Simple_; end
|
76
|
+
class CAPTION < PreserveSpace_; end
|
77
|
+
class TR < Simple_; end
|
78
|
+
class TH < PreserveSpace_; end
|
79
|
+
class TD < PreserveSpace_; end
|
80
|
+
class BR < Simple_; end
|
81
|
+
class HR < Simple_; end
|
82
|
+
|
83
|
+
module Hn
|
84
|
+
def self.new(level, attr={}, &proc)
|
85
|
+
raise ArgumentError unless 1<=level && level<=6
|
86
|
+
klass = EimXML::XHTML.const_get("H#{level}")
|
87
|
+
klass.new(attr, &proc)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class TEXTAREA < PreserveSpace_; end
|
92
|
+
|
93
|
+
class INPUT < Base_
|
94
|
+
def initialize(opt={})
|
95
|
+
super(:input, opt)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class BUTTON < Base_
|
100
|
+
def initialize(opt={})
|
101
|
+
super(:button, opt)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class SUBMIT < BUTTON
|
106
|
+
def initialize(opt={})
|
107
|
+
super(opt.merge(:type=>:submit))
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class HIDDEN < INPUT
|
112
|
+
def initialize(opt={})
|
113
|
+
super(opt.merge(:type=>:hidden))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class TEXT < INPUT
|
118
|
+
def initialize(opt={})
|
119
|
+
super(opt.merge(:type=>:text))
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class PASSWORD < INPUT
|
124
|
+
def initialize(opt={})
|
125
|
+
super(opt.merge(:type=>:password))
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
PRESERVE_SPACES = [PreserveSpace_]
|
130
|
+
class Formatter < EimXML::Formatter
|
131
|
+
def self.write(element, opt={})
|
132
|
+
EimXML::Formatter.write(element, opt.merge(:preservers=>PRESERVE_SPACES))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/eim_xml.rb
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
# Easy IMplementation of XML
|
2
|
+
#
|
3
|
+
# Copyright (C) 2006, KURODA Hiraku <hiraku@hinet.mydns.jp>
|
4
|
+
# You can redistribute it and/or modify it under GPL2.
|
5
|
+
#
|
6
|
+
|
7
|
+
module EimXML
|
8
|
+
XML_DECLARATION = %[<?xml version="1.0"?>]
|
9
|
+
|
10
|
+
class PCString
|
11
|
+
attr_reader :encoded_string, :src
|
12
|
+
alias to_s encoded_string
|
13
|
+
|
14
|
+
def self.encode(s)
|
15
|
+
s.to_s.gsub(/[&\"\'<>]/) do |m|
|
16
|
+
case m
|
17
|
+
when "&"
|
18
|
+
"&"
|
19
|
+
when '"'
|
20
|
+
"""
|
21
|
+
when "'"
|
22
|
+
"'"
|
23
|
+
when "<"
|
24
|
+
"<"
|
25
|
+
when ">"
|
26
|
+
">"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.[](obj)
|
32
|
+
obj.is_a?(PCString) ? obj : PCString.new(obj)
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(s, encoded=false)
|
36
|
+
@src = s
|
37
|
+
@encoded_string = encoded ? s : PCString.encode(s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
other.is_a?(PCString) ? @encoded_string==other.encoded_string : self==PCString.new(other)
|
42
|
+
end
|
43
|
+
|
44
|
+
def write_to(out="")
|
45
|
+
out << encoded_string
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Comment
|
50
|
+
def initialize(text)
|
51
|
+
raise ArgumentError, "Can not include '--'" if text =~ /--/
|
52
|
+
@text = text
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_to(out="")
|
56
|
+
out << "<!-- #{@text} -->"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Element
|
61
|
+
attr_reader :name, :attributes, :contents
|
62
|
+
|
63
|
+
NEST = " "
|
64
|
+
|
65
|
+
def initialize(name, attributes={})
|
66
|
+
@name = name.to_sym
|
67
|
+
@attributes = Hash.new
|
68
|
+
@contents = Array.new
|
69
|
+
|
70
|
+
attributes.each do |k, v|
|
71
|
+
@attributes[k.to_sym] = v
|
72
|
+
end
|
73
|
+
|
74
|
+
yield(self) if block_given?
|
75
|
+
end
|
76
|
+
|
77
|
+
def name=(new_name)
|
78
|
+
@name = new_name.to_sym
|
79
|
+
end
|
80
|
+
protected :name=
|
81
|
+
|
82
|
+
def add(v)
|
83
|
+
case v
|
84
|
+
when nil
|
85
|
+
when Array
|
86
|
+
v.each{|i| self.add(i)}
|
87
|
+
else
|
88
|
+
@contents << v
|
89
|
+
end
|
90
|
+
self
|
91
|
+
end
|
92
|
+
alias << add
|
93
|
+
|
94
|
+
def name_and_attributes(out="")
|
95
|
+
out << "#{@name}"
|
96
|
+
@attributes.each do |k, v|
|
97
|
+
next unless v
|
98
|
+
out << " #{k}='#{PCString===v ? v : PCString.encode(v.to_s)}'"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def write_to(out = "")
|
103
|
+
out << "<"
|
104
|
+
name_and_attributes(out)
|
105
|
+
|
106
|
+
if @contents.empty?
|
107
|
+
out << " />"
|
108
|
+
else
|
109
|
+
out << ">"
|
110
|
+
@contents.each do |c|
|
111
|
+
case c
|
112
|
+
when Element
|
113
|
+
c.write_to(out)
|
114
|
+
when PCString
|
115
|
+
out << c.to_s
|
116
|
+
else
|
117
|
+
out << PCString.encode(c.to_s)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
out << "</#{@name}>"
|
121
|
+
end
|
122
|
+
out
|
123
|
+
end
|
124
|
+
alias :to_s :write_to
|
125
|
+
alias :inspect :to_s
|
126
|
+
|
127
|
+
def ==(xml)
|
128
|
+
return false unless xml.is_a?(Element)
|
129
|
+
@name==xml.name && @attributes==xml.attributes && @contents==xml.contents
|
130
|
+
end
|
131
|
+
|
132
|
+
def add_attribute(key, value)
|
133
|
+
@attributes[key.to_sym] = value
|
134
|
+
end
|
135
|
+
alias []= add_attribute
|
136
|
+
|
137
|
+
def [](key)
|
138
|
+
if key.is_a?(Fixnum)
|
139
|
+
@contents[key]
|
140
|
+
else
|
141
|
+
@attributes[key.to_sym]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def del_attribute(key)
|
146
|
+
@attributes.delete(key.to_sym)
|
147
|
+
end
|
148
|
+
|
149
|
+
def pcstring_contents
|
150
|
+
@contents.select{|c| c.is_a?(String)||c.is_a?(PCString)}.map{|c| c.is_a?(String) ? PCString.new(c) : c}
|
151
|
+
end
|
152
|
+
|
153
|
+
def match(obj, attr=nil)
|
154
|
+
return match(Element.new(obj, attr)) if attr
|
155
|
+
return obj=~@name.to_s if obj.is_a?(Regexp)
|
156
|
+
return @name==obj if obj.is_a?(Symbol)
|
157
|
+
return is_a?(obj) if obj.is_a?(Module)
|
158
|
+
|
159
|
+
raise ArgumentError unless obj.is_a?(Element)
|
160
|
+
|
161
|
+
return false unless @name==obj.name
|
162
|
+
|
163
|
+
obj.attributes.all? do |k, v|
|
164
|
+
(v.nil? && !@attributes.include?(k)) ||
|
165
|
+
(@attributes.include?(k) && (v.is_a?(Regexp) ? v =~ @attributes[k] : PCString[v] == PCString[@attributes[k]]))
|
166
|
+
end and obj.contents.all? do |i|
|
167
|
+
case i
|
168
|
+
when Element
|
169
|
+
has_element?(i)
|
170
|
+
when String
|
171
|
+
pcstring_contents.include?(PCString.new(i))
|
172
|
+
when PCString
|
173
|
+
pcstring_contents.include?(i)
|
174
|
+
when Regexp
|
175
|
+
@contents.any?{|c| c.is_a?(String) and i=~c}
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
alias :=~ :match
|
180
|
+
|
181
|
+
def has?(obj, attr=nil)
|
182
|
+
return has?(Element.new(obj, attr)) if attr
|
183
|
+
|
184
|
+
@contents.any? do |i|
|
185
|
+
if i.is_a?(Element)
|
186
|
+
i.match(obj) || i.has?(obj)
|
187
|
+
else
|
188
|
+
obj.is_a?(Module) && i.is_a?(obj)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
alias has_element? has?
|
193
|
+
alias include? has?
|
194
|
+
|
195
|
+
def find(obj, dst=Element.new(:found))
|
196
|
+
return find(Element.new(obj, dst)) if dst.is_a?(Hash)
|
197
|
+
|
198
|
+
dst << self if match(obj)
|
199
|
+
@contents.each do |i|
|
200
|
+
case
|
201
|
+
when i.is_a?(Element)
|
202
|
+
i.find(obj, dst)
|
203
|
+
when obj.is_a?(Module) && i.is_a?(obj)
|
204
|
+
dst << i
|
205
|
+
end
|
206
|
+
end
|
207
|
+
dst
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Test for eim_xml/assertions.rb
|
2
|
+
#
|
3
|
+
# Copyright (C) 2006, KURODA Hiraku <hiraku@hinet.mydns.jp>
|
4
|
+
# You can redistribute it and/or modify it under GPL2.
|
5
|
+
|
6
|
+
require "test/unit"
|
7
|
+
require "eim_xml/assertions"
|
8
|
+
|
9
|
+
class EimXMLAssertionsTest < Test::Unit::TestCase
|
10
|
+
include EimXML
|
11
|
+
include EimXML::Assertions
|
12
|
+
|
13
|
+
def test_assert_has
|
14
|
+
e = Element.new(:tag) do |e|
|
15
|
+
e <<= Element.new(:sub)
|
16
|
+
end
|
17
|
+
|
18
|
+
assert_nothing_raised do
|
19
|
+
assert_has(:sub, e)
|
20
|
+
end
|
21
|
+
|
22
|
+
a = assert_raises(Test::Unit::AssertionFailedError) do
|
23
|
+
assert_has(:no, e)
|
24
|
+
end
|
25
|
+
assert(!a.backtrace.any?{ |i|
|
26
|
+
i=~/eim_xml\/assertions\.rb/
|
27
|
+
})
|
28
|
+
end
|
29
|
+
end
|
data/spec/dsl_spec.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
require "eim_xml/dsl"
|
2
|
+
|
3
|
+
module Module.new::M
|
4
|
+
include EimXML
|
5
|
+
EDSL = EimXML::DSL
|
6
|
+
|
7
|
+
describe EimXML::DSL do
|
8
|
+
it "scope is in instance of DSL" do
|
9
|
+
outer = inner = nil
|
10
|
+
e3 = e2 = nil
|
11
|
+
block_executed = false
|
12
|
+
e = EDSL.element(:out, :k1=>"v1") do
|
13
|
+
outer = self
|
14
|
+
e2 = element(:in, :k2=>"v2") do
|
15
|
+
block_executed = true
|
16
|
+
inner = self
|
17
|
+
e3 = element(:deep)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
block_executed.should == true
|
22
|
+
outer.should be_kind_of(EDSL)
|
23
|
+
inner.should be_kind_of(EDSL)
|
24
|
+
outer.should be_equal(inner)
|
25
|
+
|
26
|
+
e.name.should == :out
|
27
|
+
e[:k1].should == "v1"
|
28
|
+
e[0].name.should == :in
|
29
|
+
e[0][:k2].should == "v2"
|
30
|
+
e[0][0].name.should == :deep
|
31
|
+
e2.should be_equal(e[0])
|
32
|
+
e3.should be_equal(e[0][0])
|
33
|
+
end
|
34
|
+
|
35
|
+
it "#comment" do
|
36
|
+
Comment.should_receive(:new).with("comment").and_return(:success)
|
37
|
+
EDSL.comment("comment").should == :success
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#import_variables" do
|
41
|
+
d = EDSL.new
|
42
|
+
o = Object.new
|
43
|
+
o.instance_variable_set("@v1", 1)
|
44
|
+
o.instance_variable_set("@v2", "2")
|
45
|
+
o.instance_variable_set("@_v3", :t)
|
46
|
+
o.instance_variable_set("@__v4", 4)
|
47
|
+
o.instance_variable_set("@_container", :t)
|
48
|
+
orig_c = d.instance_variable_get("@_container")
|
49
|
+
|
50
|
+
d.import_variables(o).should be_equal(d)
|
51
|
+
|
52
|
+
d.instance_variable_get("@_container").should == orig_c
|
53
|
+
d.instance_variables.map(&:to_s).sort.should == ["@v1", "@v2", "@__v4"].sort
|
54
|
+
d.instance_variable_get("@v1").should == 1
|
55
|
+
d.instance_variable_get("@v2").should == "2"
|
56
|
+
d.instance_variable_get("@__v4").should == 4
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#_push" do
|
60
|
+
before do
|
61
|
+
m = Module.new
|
62
|
+
class m::D < EimXML::DSL
|
63
|
+
def call_push(c)
|
64
|
+
_push(c) do
|
65
|
+
element(:e)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def exec
|
70
|
+
element(:e) do
|
71
|
+
element(:f)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
@D = m::D
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should return given container" do
|
79
|
+
a = []
|
80
|
+
@D.new.call_push(a).should be_equal(a)
|
81
|
+
a.should == [EimXML::Element.new(:e)]
|
82
|
+
|
83
|
+
@D.new.exec.should == EimXML::Element.new(:e).add(EimXML::Element.new(:f))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "Subclass of BaseDSL" do
|
89
|
+
class DSL1 < EimXML::BaseDSL
|
90
|
+
register([EimXML::Element, "call"])
|
91
|
+
register(Hash)
|
92
|
+
register(String, Array, Object)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "register" do
|
96
|
+
lambda{EDSL.call(:dummy)}.should raise_error(NoMethodError)
|
97
|
+
lambda{BaseDSL.call(:dummy)}.should raise_error(NoMethodError)
|
98
|
+
lambda{DSL1.element(:dummy)}.should raise_error(NoMethodError)
|
99
|
+
DSL1.call(:dummy).should be_kind_of(Element)
|
100
|
+
DSL1.hash.should be_kind_of(Hash)
|
101
|
+
DSL1.string.should be_kind_of(String)
|
102
|
+
DSL1.array.should be_kind_of(Array)
|
103
|
+
DSL1.object.should be_kind_of(Object)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe EimXML::OpenDSL do
|
108
|
+
it "scope of block is one of outside" do
|
109
|
+
@scope_checker_variable = 1
|
110
|
+
block_executed = false
|
111
|
+
d = OpenDSL.new do |d|
|
112
|
+
block_executed = true
|
113
|
+
d.should be_kind_of(OpenDSL)
|
114
|
+
d.container.should be_nil
|
115
|
+
d.element(:base, :key1=>"v1") do
|
116
|
+
@scope_checker_variable.should == 1
|
117
|
+
self.should_not be_kind_of(Element)
|
118
|
+
d.container.should be_kind_of(Element)
|
119
|
+
d.container.should == Element.new(:base, :key1=>"v1")
|
120
|
+
d.element(:sub, :key2=>"v2") do
|
121
|
+
d.container.should be_kind_of(Element)
|
122
|
+
d.container.should == Element.new(:sub, :key2=>"v2")
|
123
|
+
end
|
124
|
+
d.element(:sub2).should == Element.new(:sub2)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
block_executed.should be_true
|
128
|
+
end
|
129
|
+
|
130
|
+
it "DSL methods return element" do
|
131
|
+
d = OpenDSL.new
|
132
|
+
d.container.should be_nil
|
133
|
+
r = d.element(:base, :key1=>"v1") do
|
134
|
+
d.element(:sub, :key2=>"v2")
|
135
|
+
end
|
136
|
+
r.should == EDSL.element(:base, :key1=>"v1") do
|
137
|
+
element(:sub, :key2=>"v2")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
it "DSL method's block given instance of OpenDSL" do
|
142
|
+
e = OpenDSL.new.element(:base) do |d|
|
143
|
+
d.should be_kind_of(OpenDSL)
|
144
|
+
d.container.name.should == :base
|
145
|
+
d.element(:sub) do |d2|
|
146
|
+
d2.should be_equal(d)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
e.should == EDSL.element(:base) do
|
151
|
+
element(:sub)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
it "ensure reset container when error raised" do
|
156
|
+
OpenDSL.new do |d|
|
157
|
+
begin
|
158
|
+
d.element(:base) do
|
159
|
+
begin
|
160
|
+
d.element(:sub) do
|
161
|
+
raise "OK"
|
162
|
+
end
|
163
|
+
rescue RuntimeError => e
|
164
|
+
raise unless e.message=="OK"
|
165
|
+
d.container.name.should == :base
|
166
|
+
raise
|
167
|
+
end
|
168
|
+
end
|
169
|
+
rescue RuntimeError => e
|
170
|
+
raise unless e.message=="OK"
|
171
|
+
d.container.should == nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
it "respond to add" do
|
177
|
+
r = OpenDSL.new.element(:base) do |d|
|
178
|
+
d.add "text"
|
179
|
+
d.element(:sub) do
|
180
|
+
s = Element.new(:sub)
|
181
|
+
s.add("sub text")
|
182
|
+
d.add("sub text").should == s
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
r.should == EDSL.element(:base) do
|
187
|
+
add "text"
|
188
|
+
element(:sub) do
|
189
|
+
add "sub text"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it "respond to <<" do
|
195
|
+
r = OpenDSL.new.element(:base) do |d|
|
196
|
+
b = Element.new(:base)
|
197
|
+
b << "text" << "next"
|
198
|
+
(d << "text" << "next").should == b
|
199
|
+
end
|
200
|
+
r.should == EDSL.element(:base) do
|
201
|
+
add "text"
|
202
|
+
add "next"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it "can call directly element method" do
|
207
|
+
r = OpenDSL.element(:base) do |d|
|
208
|
+
d.element(:sub)
|
209
|
+
d.element(:sub2)
|
210
|
+
end
|
211
|
+
r.should == EDSL.element(:base) do
|
212
|
+
element(:sub)
|
213
|
+
element(:sub2)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|