ad_hoc_template 0.0.1 → 0.1.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.
@@ -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