ad_hoc_template 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,170 +1,8 @@
1
1
  require "ad_hoc_template/version"
2
- require "pseudohiki/inlineparser"
3
- require "htmlelement"
2
+ require "ad_hoc_template/parser"
3
+ require "ad_hoc_template/record_reader"
4
4
 
5
5
  module AdHocTemplate
6
- class Parser < TreeStack
7
- class TagNode < Parser::Node
8
- attr_reader :type
9
-
10
- def push(node=TreeStack::Node.new)
11
- node[0] = assign_type(node[0]) if self.empty?
12
- super
13
- end
14
-
15
- def assign_type(first_leaf)
16
- return first_leaf unless first_leaf.kind_of? String and /^\S/o.match(first_leaf)
17
- @type, first_leaf_content = first_leaf.split(/\s+/o, 2)
18
- first_leaf_content||""
19
- end
20
- private :assign_type
21
-
22
- def contains_any_value_assigned_tag_node?(record)
23
- self.select {|n| n.kind_of?(TagNode) }.each do |node|
24
- val = record[node.join.strip]
25
- return true if val and not val.empty?
26
- end
27
- false
28
- end
29
- end
30
-
31
- class IterationTagNode < TagNode; end
32
- class Leaf < Parser::Leaf; end
33
-
34
- HEAD, TAIL = {}, {}
35
-
36
- [[TagNode, "<%", "%>"],
37
- [IterationTagNode, "<%#", "#%>"]].each do |type, head, tail|
38
- HEAD[head] = type
39
- TAIL[tail] = type
40
- end
41
-
42
- TOKEN_PAT = PseudoHiki.compile_token_pat(HEAD.keys, TAIL.keys)
43
-
44
- def self.split_into_tokens(str)
45
- tokens = []
46
-
47
- while m = TOKEN_PAT.match(str)
48
- tokens.push m.pre_match unless m.pre_match.empty?
49
- tokens.push m[0]
50
- str = m.post_match
51
- end
52
-
53
- tokens.push str unless str.empty?
54
- tokens
55
- end
56
-
57
- def self.parse(str)
58
- new(str).parse.tree
59
- end
60
-
61
- def initialize(str)
62
- @tokens = Parser.split_into_tokens(str)
63
- super()
64
- end
65
-
66
- def parse
67
- while token = @tokens.shift
68
- next if TAIL[token] == current_node.class and self.pop
69
- next if HEAD[token] and self.push HEAD[token].new
70
- self.push Leaf.create(token)
71
- end
72
-
73
- self
74
- end
75
- end
76
-
77
- module RecordReader
78
- SEPARATOR = /:\s*/o
79
- BLOCK_HEAD = /\A\/\/@/o
80
- EMPTY_LINE = /\A\r?\n\Z/o
81
- ITERATION_MARK = /\A#/o
82
-
83
- def self.remove_leading_empty_lines(lines)
84
- until lines.empty? or /\S/o.match(lines.first)
85
- lines.shift
86
- end
87
- end
88
-
89
- def self.strip_blank_lines(block)
90
- remove_leading_empty_lines(block)
91
- block.pop while not block.empty? and EMPTY_LINE.match(block.last)
92
- end
93
-
94
- def self.read_key_value_list(lines, record)
95
- while line = lines.shift and not EMPTY_LINE.match(line)
96
- key, val = line.chomp.split(SEPARATOR, 2)
97
- record[key] = val
98
- end
99
-
100
- record
101
- end
102
-
103
- def self.read_block(lines, record, block_head)
104
- block = []
105
-
106
- while line = lines.shift
107
- if m = BLOCK_HEAD.match(line)
108
- strip_blank_lines(block)
109
- record[block_head] = block.join
110
- return m.post_match.chomp
111
- end
112
-
113
- block.push(line)
114
- end
115
-
116
- strip_blank_lines(block)
117
- record[block_head] = block.join
118
- end
119
-
120
- def self.read_block_part(lines, record, block_head)
121
- until lines.empty? or not block_head
122
- block_head = read_block(lines, record, block_head)
123
- end
124
- end
125
-
126
- def self.read_iteration_block(lines, record, block_head)
127
- records = []
128
-
129
- while line = lines.shift
130
- if m = BLOCK_HEAD.match(line)
131
- record[block_head] = records
132
- return m.post_match.chomp
133
- elsif EMPTY_LINE.match(line)
134
- next
135
- else
136
- lines.unshift line
137
- records.push read_key_value_list(lines, {})
138
- end
139
- end
140
-
141
- record[block_head] = records
142
- nil
143
- end
144
-
145
- def self.read_iteration_block_part(lines, record, block_head)
146
- while not lines.empty? and block_head and ITERATION_MARK.match(block_head)
147
- block_head = read_iteration_block(lines, record, block_head)
148
- end
149
-
150
- block_head
151
- end
152
-
153
- def self.read_record(input)
154
- lines = input.each_line.to_a
155
- record = read_key_value_list(lines, {})
156
- remove_leading_empty_lines(lines)
157
-
158
- unless lines.empty?
159
- m = BLOCK_HEAD.match(lines.shift)
160
- block_head = read_iteration_block_part(lines, record, m.post_match.chomp)
161
- read_block_part(lines, record, block_head) if block_head
162
- end
163
-
164
- record
165
- end
166
- end
167
-
168
6
  class DefaultTagFormatter
169
7
  def find_function(tag_type)
170
8
  FUNCTION_TABLE[tag_type]||:default
@@ -178,7 +16,7 @@ module AdHocTemplate
178
16
  record[var]||"[#{var}]"
179
17
  end
180
18
 
181
- def html_encode(var ,record)
19
+ def html_encode(var, record)
182
20
  HtmlElement.escape(record[var]||var)
183
21
  end
184
22
 
@@ -188,16 +26,24 @@ module AdHocTemplate
188
26
  }
189
27
  end
190
28
 
191
- class Converter
192
- def self.convert(record_data, template, formatter=DefaultTagFormatter.new)
193
- tree = AdHocTemplate::Parser.parse(template)
194
- record = AdHocTemplate::RecordReader.read_record(record_data)
195
- AdHocTemplate::Converter.new(record, formatter).format(tree)
29
+ class DataLoader
30
+ def self.format(template, record, tag_formatter=DefaultTagFormatter.new)
31
+ if record.kind_of? Array
32
+ return format_multi_records(template, record, tag_formatter)
33
+ end
34
+ new(record, tag_formatter).format(template)
35
+ end
36
+
37
+ def self.format_multi_records(template, records,
38
+ tag_formatter=DefaultTagFormatter.new)
39
+ records.map do |record|
40
+ new(record, tag_formatter).format(template)
41
+ end.join
196
42
  end
197
43
 
198
- def initialize(record, formatter=DefaultTagFormatter.new)
44
+ def initialize(record, tag_formatter=DefaultTagFormatter.new)
199
45
  @record = record
200
- @formatter = formatter
46
+ @tag_formatter = tag_formatter
201
47
  end
202
48
 
203
49
  def visit(tree)
@@ -214,13 +60,13 @@ module AdHocTemplate
214
60
  end
215
61
 
216
62
  def format_iteration_tag(tag_node)
217
- sub_records = @record["#"+(tag_node.type||"".freeze)]||[@record]
63
+ sub_records = @record[tag_node.type]||[@record]
218
64
  tag_node = Parser::TagNode.new.concat(tag_node.clone)
219
65
 
220
66
  sub_records.map do |record|
221
67
  if tag_node.contains_any_value_assigned_tag_node?(record)
222
- converter = AdHocTemplate::Converter.new(record, @formatter)
223
- tag_node.map {|leaf| leaf.accept(converter) }.join
68
+ data_loader = AdHocTemplate::DataLoader.new(record, @tag_formatter)
69
+ tag_node.map {|leaf| leaf.accept(data_loader) }.join
224
70
  else
225
71
  "".freeze
226
72
  end
@@ -229,11 +75,18 @@ module AdHocTemplate
229
75
 
230
76
  def format_tag(tag_node)
231
77
  leafs = tag_node.map {|leaf| leaf.accept(self) }
232
- @formatter.format(tag_node.type, leafs.join.strip, @record)
78
+ @tag_formatter.format(tag_node.type, leafs.join.strip, @record)
233
79
  end
234
80
 
235
81
  def format(tree)
236
82
  tree.accept(self).join
237
83
  end
238
84
  end
85
+
86
+ def self.convert(record_data, template, tag_type=:default, data_format=:default,
87
+ tag_formatter=DefaultTagFormatter.new)
88
+ tree = Parser.parse(template, tag_type)
89
+ record = RecordReader.read_record(record_data, data_format)
90
+ DataLoader.format(tree, record, tag_formatter)
91
+ end
239
92
  end