eimxml 0.0.2 → 0.0.3.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.
@@ -0,0 +1,123 @@
1
+ require "eim_xml"
2
+
3
+ module EimXML
4
+ class Formatter
5
+ attr_reader :out
6
+
7
+ def self.write(element, opt={})
8
+ opt = {:out=>""}.merge(opt)
9
+ new(opt).write(element)
10
+ opt[:out]
11
+ end
12
+
13
+ def initialize(opt)
14
+ @out = opt[:out]
15
+ @preservers = opt[:preservers]
16
+ @preserve_space = false
17
+ @indent_string = " "
18
+ @indent_depth = 0
19
+ @option = opt.dup.tap{|h| [:out, :preservers].each{|k| h.delete(k)}}
20
+ end
21
+
22
+ def write(src)
23
+ case src
24
+ when ElementWrapper
25
+ write_wrapper(src)
26
+ when Comment
27
+ write_comment(src)
28
+ when Element
29
+ write_element(src)
30
+ when PCString
31
+ write_pcstring(src)
32
+ else
33
+ write_string(src.to_s)
34
+ end
35
+ end
36
+
37
+ def indent(&proc)
38
+ @indent_depth += 1
39
+ proc.call
40
+ ensure
41
+ @indent_depth -= 1
42
+ end
43
+
44
+ def preserve_space_element?(elm)
45
+ @preservers && @preservers.any? do |e|
46
+ case e
47
+ when Symbol
48
+ e==elm.name
49
+ when Class
50
+ e===elm
51
+ end
52
+ end
53
+ end
54
+
55
+ def write_indent
56
+ out << @indent_string*@indent_depth unless @preserve_space
57
+ end
58
+
59
+ def write_newline
60
+ out << "\n" unless @preserve_space
61
+ end
62
+
63
+ def write_comment(c)
64
+ write_indent
65
+ c.write_to(out)
66
+ write_newline
67
+ end
68
+
69
+ def write_contents_of(elm)
70
+ flag = @preserve_space
71
+ @preserve_space = true if preserve_space_element?(elm)
72
+ write_newline
73
+ indent do
74
+ elm.contents.each do |c|
75
+ write(c)
76
+ end
77
+ end
78
+ write_indent
79
+ ensure
80
+ @preserve_space = flag
81
+ end
82
+
83
+ def write_element(elm)
84
+ write_indent
85
+ out << "<"
86
+ elm.name_and_attributes(out)
87
+ case elm.contents.size
88
+ when 0
89
+ out << " />"
90
+ write_newline
91
+ else
92
+ out << ">"
93
+ write_contents_of(elm)
94
+ out << "</#{elm.name}>"
95
+ write_newline
96
+ end
97
+ end
98
+
99
+ def write_pcstring(pcs)
100
+ pcs.encoded_string.each_line do |l|
101
+ write_indent
102
+ out << l
103
+ end
104
+ write_newline
105
+ end
106
+
107
+ def write_string(str)
108
+ PCString.encode(str).each_line do |l|
109
+ write_indent
110
+ out << l
111
+ end
112
+ write_newline
113
+ end
114
+
115
+ def write_wrapper(wrapper)
116
+ wrapper.each(@option) do |i|
117
+ write(i)
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ require "eim_xml/formatter/element_wrapper"
@@ -0,0 +1,7 @@
1
+ class EimXML::Formatter
2
+ class ElementWrapper
3
+ def each(option, &proc)
4
+ contents(option).each(&proc)
5
+ end
6
+ end
7
+ end
@@ -16,32 +16,23 @@ module EimXML
16
16
  module RE
17
17
  EMPTY_ELEMENT = /<([^>]*?)\/>/
18
18
  START_TAG = /<([^>]*?([^\/>]\s*))>/
19
- END_TAG = /<\/(\S+)\s*>/
19
+ END_TAG = /<\/(\S+?)\s*>/
20
20
  ATTRIBUTE = /\s+([^=\s]+)\s*=\s*('(.*?)'|"(.*?)")/m
21
21
  STRING = /[^<]+/
22
22
  end
23
23
 
24
- def initialize(src, *space_holders)
24
+ def initialize(src)
25
25
  @scanner = StringScanner.new(src)
26
- @space_holders = []
27
- @space_holder_res = []
28
- space_holders.each do |i|
29
- if i.is_a?(Regexp)
30
- @space_holder_res << i
31
- else
32
- @space_holders << i.to_sym
33
- end
34
- end
26
+ @scanner.scan(/\s*<\?.*?\?>\s*/)
35
27
  end
36
28
 
37
- def parse(hold_space = false)
38
- @scanner.scan(/\s+/) unless hold_space
29
+ def parse
39
30
  if @scanner.scan(RE::EMPTY_ELEMENT)
40
- parse_empty_element(hold_space)
31
+ parse_empty_element
41
32
  elsif @scanner.scan(RE::START_TAG)
42
- parse_start_tag(hold_space)
33
+ parse_start_tag
43
34
  elsif @scanner.scan(RE::STRING)
44
- parse_string(hold_space)
35
+ parse_string
45
36
  else
46
37
  nil
47
38
  end
@@ -55,43 +46,26 @@ module EimXML
55
46
  end
56
47
  protected :parse_tag
57
48
 
58
- def space_holder?(ename)
59
- return true if @space_holders.include?(ename)
60
- s = ename.to_s
61
- @space_holder_res.each do |re|
62
- return true if re=~s
63
- end
64
- false
65
- end
66
-
67
- def parse_empty_element(hold_space)
68
- e = parse_tag
69
- hold_space = space_holder?(e.name) unless hold_space
70
- e.hold_space if hold_space
71
- e
49
+ def parse_empty_element
50
+ parse_tag
72
51
  end
73
52
  protected :parse_empty_element
74
53
 
75
- def parse_start_tag(hold_space)
54
+ def parse_start_tag
76
55
  e = parse_tag
77
- hold_space = space_holder?(e.name) unless hold_space
78
56
 
79
- e.hold_space if hold_space
80
- @scanner.scan(/\s*/) unless hold_space
81
57
  until @scanner.scan(RE::END_TAG)
82
- c = parse(hold_space)
58
+ c = parse
83
59
  raise ParseError.new("Syntax error.") unless c
84
60
  e << c
85
- @scanner.scan(/\s*/) unless hold_space
86
61
  end
87
62
  raise ParseError.new("End tag mismatched.") unless @scanner[1].to_sym==e.name
88
63
  e
89
64
  end
90
65
  protected :parse_start_tag
91
66
 
92
- def parse_string(hold_space)
67
+ def parse_string
93
68
  s = @scanner[0]
94
- s = s.strip unless hold_space
95
69
  s = s.gsub(/&(amp|quot|apos|lt|gt);/) do
96
70
  case $1
97
71
  when "amp"
@@ -104,8 +78,6 @@ module EimXML
104
78
  "<"
105
79
  when "gt"
106
80
  ">"
107
- else
108
- raise "must not happen"
109
81
  end
110
82
  end
111
83
  PCString.new(s)
@@ -1,16 +1,11 @@
1
1
  require "eim_xml"
2
+ require "eim_xml/formatter"
2
3
 
3
4
  module EimXML::XHTML
4
5
  module DocType
5
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">]
6
7
  end
7
8
 
8
- class DSL < EimXML::BaseDSL
9
- end
10
-
11
- class OpenDSL < EimXML::OpenDSL
12
- end
13
-
14
9
  class Base_ < EimXML::Element
15
10
  end
16
11
 
@@ -20,106 +15,139 @@ module EimXML::XHTML
20
15
  XHTML = "http://www.w3.org/1999/xhtml"
21
16
  end
22
17
 
23
- def initialize(attributes=nil)
18
+ def initialize(attributes={})
24
19
  super(:html, attributes)
25
20
  end
26
21
 
27
- def to_xml(s="")
28
- s << @prefix << "\n" if @prefix
29
- super(s)
22
+ def write_to(out="")
23
+ out << @prefix << "\n" if @prefix
24
+ super
30
25
  end
31
26
  end
32
27
 
33
28
  class Simple_ < Base_
34
- def initialize(attributes=nil)
29
+ def initialize(attributes={})
35
30
  super(self.class.name[/.*::(.*)/, 1].downcase.to_sym, attributes)
36
31
  end
37
32
  end
38
33
 
34
+ class PreserveSpace_ < Base_
35
+ def initialize(name={}, attributes={})
36
+ if name.is_a?(Hash)
37
+ super(self.class.name[/.*::(.*)/, 1].downcase.to_sym, name)
38
+ else
39
+ super(name, attributes)
40
+ end
41
+ end
42
+ end
43
+
39
44
  class HEAD < Simple_; end
40
45
  class META < Simple_; end
41
46
  class LINK < Simple_; end
42
- class STYLE < Simple_; end
43
- class SCRIPT < Simple_; end
47
+ class IMG < Simple_; end
48
+ class STYLE < PreserveSpace_; end
49
+ class SCRIPT < PreserveSpace_; end
44
50
  class TITLE < Simple_; end
45
51
  class BODY < Simple_; end
46
- class PRE < Simple_
47
- def initialize(attributes=nil)
52
+ class PRE < PreserveSpace_; end
53
+ class FORM < Simple_
54
+ def initialize(attributes={})
55
+ if attributes
56
+ if s = attributes.delete(:session)
57
+ name = attributes.delete(:session_name) || "token"
58
+ require "digest/sha1"
59
+ token = s[name] ||= Digest::SHA1.hexdigest("#{$$}#{Time.now}#{rand}")
60
+ end
61
+ end
48
62
  super
49
- hold_space
63
+ add(HIDDEN.new(:name=>name, :value=>token)) if token
50
64
  end
51
65
  end
52
- class FORM < Simple_; end
53
- class H1 < Simple_; end
54
- class H2 < Simple_; end
55
- class H3 < Simple_; end
56
- class H4 < Simple_; end
57
- class H5 < Simple_; end
58
- class H6 < Simple_; end
59
- class P < Simple_; end
60
- class A < Simple_; end
61
- class EM < Simple_; end
62
- class STRONG < Simple_; end
66
+ class H1 < PreserveSpace_; end
67
+ class H2 < PreserveSpace_; end
68
+ class H3 < PreserveSpace_; end
69
+ class H4 < PreserveSpace_; end
70
+ class H5 < PreserveSpace_; end
71
+ class H6 < PreserveSpace_; end
72
+ class P < PreserveSpace_; end
73
+ class A < PreserveSpace_; end
74
+ class EM < PreserveSpace_; end
75
+ class STRONG < PreserveSpace_; end
63
76
  class DIV < Simple_; end
77
+ class SPAN < PreserveSpace_; end
64
78
  class UL < Simple_; end
65
79
  class OL < Simple_; end
66
- class LI < Simple_; end
80
+ class LI < PreserveSpace_; end
67
81
  class DL < Simple_; end
68
- class DT < Simple_; end
69
- class DD < Simple_; end
82
+ class DT < PreserveSpace_; end
83
+ class DD < PreserveSpace_; end
70
84
  class TABLE < Simple_; end
71
- class CAPTION < Simple_; end
85
+ class CAPTION < PreserveSpace_; end
72
86
  class TR < Simple_; end
73
- class TH < Simple_; end
74
- class TD < Simple_; end
87
+ class TH < PreserveSpace_; end
88
+ class TD < PreserveSpace_; end
89
+ class BR < Simple_; end
90
+ class HR < Simple_; end
91
+ class SELECT < Simple_; end
92
+ class OPTION < Simple_; end
93
+
75
94
 
76
95
  module Hn
77
- def self.new(level, attr=nil, &proc)
96
+ def self.new(level, attr={}, &proc)
78
97
  raise ArgumentError unless 1<=level && level<=6
79
98
  klass = EimXML::XHTML.const_get("H#{level}")
80
99
  klass.new(attr, &proc)
81
100
  end
82
101
  end
83
102
 
84
- class TEXTAREA < Base_
85
- def initialize(name, opt={})
86
- super(:textarea, {:name=>name}.merge(opt))
103
+ class TEXTAREA < PreserveSpace_; end
104
+
105
+ class INPUT < Base_
106
+ def initialize(opt={})
107
+ super(:input, opt)
87
108
  end
88
109
  end
89
110
 
90
- class INPUT < Base_
91
- def initialize(type, name, value, opt={})
92
- attr = {:type=>type}
93
- attr[:name]=name if name
94
- attr[:value]=value if value
95
- super(:input, attr.merge(opt))
111
+ class BUTTON < PreserveSpace_
112
+ def initialize(opt={})
113
+ super(:button, opt)
96
114
  end
97
115
  end
98
116
 
99
- class HIDDEN < INPUT
100
- def initialize(name, value, opt={})
101
- super(:hidden, name, value, opt)
117
+ class SUBMIT < BUTTON
118
+ def initialize(opt={})
119
+ super(opt.merge(:type=>:submit))
102
120
  end
103
121
  end
104
122
 
105
- class SUBMIT < INPUT
123
+ class HIDDEN < INPUT
106
124
  def initialize(opt={})
107
- opt = opt.dup
108
- super(:submit, opt.delete(:name), opt.delete(:value), opt)
125
+ super(opt.merge(:type=>:hidden))
109
126
  end
110
127
  end
111
128
 
112
129
  class TEXT < INPUT
113
- def initialize(name, value=nil, opt={})
114
- super(:text, name, value, opt)
130
+ def initialize(opt={})
131
+ super(opt.merge(:type=>:text))
132
+ end
133
+ end
134
+
135
+ class PASSWORD < INPUT
136
+ def initialize(opt={})
137
+ super(opt.merge(:type=>:password))
138
+ end
139
+ end
140
+
141
+ class FILE < INPUT
142
+ def initialize(opt={})
143
+ super(opt.merge(:type=>:file))
115
144
  end
116
145
  end
117
146
 
118
- constants.each do |c|
119
- v = const_get(c)
120
- if v.is_a?(Class) && /_$/ !~ v.name
121
- DSL.register v
122
- OpenDSL.register v
147
+ PRESERVE_SPACES = [PreserveSpace_]
148
+ class Formatter < EimXML::Formatter
149
+ def self.write(element, opt={})
150
+ EimXML::Formatter.write(element, opt.merge(:preservers=>PRESERVE_SPACES))
123
151
  end
124
152
  end
125
153
  end
@@ -0,0 +1,18 @@
1
+ require "eim_xml/dsl"
2
+ require "eim_xml/xhtml"
3
+
4
+ module EimXML::XHTML
5
+ class DSL < EimXML::BaseDSL
6
+ end
7
+
8
+ class OpenDSL < EimXML::OpenDSL
9
+ end
10
+
11
+ constants.each do |c|
12
+ v = const_get(c)
13
+ if v.is_a?(Class) && /_$/ !~ v.name
14
+ DSL.register v
15
+ OpenDSL.register v
16
+ end
17
+ end
18
+ end