ad_hoc_template 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac72ef7ef92a4a6aa9be31762b2cc29177cecd44
4
+ data.tar.gz: 6fd32a26232fbb869f73632610c301e470e3178b
5
+ SHA512:
6
+ metadata.gz: e6935f638dd7c1cb8979c86bbfbd653ec75a7a4aca0d7579391026b47e60840b55a4444696cef0f2203bf6a5460b95822324b7322754cd9a215fb92e357a76a7
7
+ data.tar.gz: 42d8b17110f59b24fe529029da629fa4150ce4c531b15721d47e7783da12edee4acf56086a6f3ec86b03d84197bdcf71967a9c989d4a0a784972682e6c27fe13
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ad_hoc_template.gemspec
4
+
5
+ gem 'pseudohikiparser', :git => 'https://github.com/nico-hn/PseudoHikiParser.git', :tag => '0.0.2'
6
+
7
+ group :development do
8
+ gem "bundler", "~> 1.3"
9
+ gem "rake"
10
+ gem "rspec"
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 HASHIMOTO, Naoki
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # AdHocTemplate
2
+
3
+ AdHocTemplate is a template processor with simple but sufficent rules for some ad hoc tasks.
4
+
5
+ I conceived this template as a workaroud for some tasks in a working environment completely left behind the times (maybe 10-15 years or so?), where they don't seem to know what a database is.
6
+
7
+ And I hope this tool saves you from meaningless tasks when you have to face such a situation.
8
+
9
+ ## Installation (not published to RubyGems.org yet)
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'ad_hoc_template'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install ad_hoc_template
22
+
23
+ ## Usage
24
+
25
+ The following is an example of template format:
26
+
27
+ ```
28
+ a test string with tags (<%= key1 %> and <%= key2 %>) in it
29
+
30
+ <%#iteration_block
31
+ the value of sub_key1 is <%= sub_key1 %>
32
+ the value of sub_key2 is <%= sub_key2 %>
33
+
34
+ #%>
35
+ <%= block %>
36
+ ```
37
+
38
+ And suppose you want to fill the template with sample data below:
39
+
40
+ ```
41
+ key1: value1
42
+ key2: value2
43
+ key3: value3
44
+
45
+ //@#iteration_block
46
+
47
+ sub_key1: value1-1
48
+ sub_key2: value1-2
49
+
50
+ sub_key1: value2-1
51
+ sub_key2: value2-2
52
+
53
+ //@block
54
+
55
+ the first line of block
56
+ the second line of block
57
+
58
+ the second paragraph in block
59
+
60
+ ```
61
+
62
+ 1. Save the template and sample data above as 'template.txt' and 'sample\_data.txt' respectively.
63
+ 2. Execute the following at the command line:
64
+
65
+ ```
66
+ ad_hoc_template template.txt sample_data.txt
67
+ ```
68
+
69
+ Then you will get the following result:
70
+
71
+ ```
72
+ a test string with tags (value1 and value2) in it
73
+
74
+ the value of sub_key1 is value1-1
75
+ the value of sub_key2 is value1-2
76
+
77
+ the value of sub_key1 is value2-1
78
+ the value of sub_key2 is value2-2
79
+
80
+
81
+ the first line of block
82
+ the second line of block
83
+
84
+ the second paragraph in block
85
+
86
+ ```
87
+
88
+ ## Contributing
89
+
90
+ 1. Fork it
91
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
92
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
93
+ 4. Push to the branch (`git push origin my-new-feature`)
94
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ad_hoc_template/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ad_hoc_template"
8
+ spec.version = AdHocTemplate::VERSION
9
+ spec.authors = ["HASHIMOTO, Naoki"]
10
+ spec.email = ["hashimoto.naoki@gmail.com"]
11
+ spec.description = %q{AdHocTemplate is a template processor with simple but sufficient rules for some ad hoc tasks.}
12
+ spec.summary = %q{A tiny template processor}
13
+ spec.homepage = "https://github.com/nico-hn/AdHocTemplate"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+ spec.add_runtime_dependency "pseudohikiparser", "0.0.2"
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake", "~> 10.1"
24
+ spec.add_development_dependency "rspec", "~> 3.2"
25
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ad_hoc_template'
4
+ require 'ad_hoc_template/command_line_interface'
5
+
6
+ AdHocTemplate::CommandLineInterface.new.execute
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ad_hoc_template'
4
+ require 'optparse'
5
+
6
+ module AdHocTemplate
7
+ class CommandLineInterface
8
+ attr_accessor :output_filename, :template_data, :record_data
9
+
10
+ def initialize
11
+ @formatter = AdHocTemplate::DefaultTagFormatter.new
12
+ @output_filename = nil
13
+ end
14
+
15
+ def set_encoding(given_opt)
16
+ external, internal = given_opt.split(/:/o, 2)
17
+ Encoding.default_external = external if external and not external.empty?
18
+ Encoding.default_internal = internal if internal and not internal.empty?
19
+ end
20
+
21
+ def parse_command_line_options
22
+ OptionParser.new do |opt|
23
+ opt.on("-E [ex[:in]]", "--encoding [=ex[:in]]",
24
+ "Specify the default external and internal character encodings (same as the option of MRI") do |given_opt|
25
+ self.set_encoding(given_opt)
26
+ end
27
+
28
+ opt.on("-o [output_file]", "--output [=output_file]",
29
+ "Save the result into the specified file.") do |output_file|
30
+ @output_filename = File.expand_path(output_file)
31
+ end
32
+
33
+ opt.parse!
34
+ end
35
+ end
36
+
37
+ def read_input_files
38
+ template, record = ARGV.map {|arg| File.expand_path(arg) if arg }
39
+ if template
40
+ @template_data = File.read(template)
41
+ else
42
+ STDERR.puts "No template file is given."
43
+ end
44
+
45
+ @record_data = record ? File.read(record) : ARGF.read
46
+ end
47
+
48
+ def convert
49
+ AdHocTemplate::Converter.convert(@record_data, @template_data, @formatter)
50
+ end
51
+
52
+ def open_output
53
+ if @output_filename
54
+ open(@output_filename, "wb") do |out|
55
+ yield out
56
+ end
57
+ else
58
+ yield STDOUT
59
+ end
60
+ end
61
+
62
+ def execute
63
+ parse_command_line_options
64
+ read_input_files
65
+ open_output do |out|
66
+ out.print convert
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module AdHocTemplate
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,239 @@
1
+ require "ad_hoc_template/version"
2
+ require "pseudohiki/inlineparser"
3
+ require "htmlelement"
4
+
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
+ class DefaultTagFormatter
169
+ def find_function(tag_type)
170
+ FUNCTION_TABLE[tag_type]||:default
171
+ end
172
+
173
+ def format(tag_type, var, record)
174
+ self.send(find_function(tag_type), var, record)
175
+ end
176
+
177
+ def default(var, record)
178
+ record[var]||"[#{var}]"
179
+ end
180
+
181
+ def html_encode(var ,record)
182
+ HtmlElement.escape(record[var]||var)
183
+ end
184
+
185
+ FUNCTION_TABLE = {
186
+ "=" => :default,
187
+ "h" => :html_encode
188
+ }
189
+ end
190
+
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)
196
+ end
197
+
198
+ def initialize(record, formatter=DefaultTagFormatter.new)
199
+ @record = record
200
+ @formatter = formatter
201
+ end
202
+
203
+ def visit(tree)
204
+ case tree
205
+ when Parser::IterationTagNode
206
+ format_iteration_tag(tree)
207
+ when Parser::TagNode
208
+ format_tag(tree)
209
+ when Parser::Leaf
210
+ tree.join
211
+ else
212
+ tree.map {|node| node.accept(self) }
213
+ end
214
+ end
215
+
216
+ def format_iteration_tag(tag_node)
217
+ sub_records = @record["#"+(tag_node.type||"".freeze)]||[@record]
218
+ tag_node = Parser::TagNode.new.concat(tag_node.clone)
219
+
220
+ sub_records.map do |record|
221
+ 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
224
+ else
225
+ "".freeze
226
+ end
227
+ end
228
+ end
229
+
230
+ def format_tag(tag_node)
231
+ leafs = tag_node.map {|leaf| leaf.accept(self) }
232
+ @formatter.format(tag_node.type, leafs.join.strip, @record)
233
+ end
234
+
235
+ def format(tree)
236
+ tree.accept(self).join
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,249 @@
1
+ require 'spec_helper'
2
+ require 'ad_hoc_template'
3
+
4
+ describe AdHocTemplate do
5
+ it 'should have a version number' do
6
+ expect(AdHocTemplate::VERSION).to_not be_nil
7
+ end
8
+
9
+ describe AdHocTemplate::Parser do
10
+ it "returns a tree of TagNode and Leaf" do
11
+ expect(AdHocTemplate::Parser.parse("a test string with tags (<% the first tag %> and <% the second tag %>) in it")).to eq([["a test string with tags ("],
12
+ [[" the first tag "]],
13
+ [" and "],
14
+ [[" the second tag "]],
15
+ [") in it"]])
16
+ end
17
+
18
+ it "allows to have a nested tag" do
19
+ expect(AdHocTemplate::Parser.parse("a test string with a nested tag; <% an outer tag and <% an inner tag %> %>")).to eq([["a test string with a nested tag; "],
20
+ [[" an outer tag and "],
21
+ [[" an inner tag "]],
22
+ [" "]]])
23
+ end
24
+
25
+ it "may have iteration tags." do
26
+ tree = AdHocTemplate::Parser.parse("a test string with a nested tag: <%# an iteration tag and <% an inner tag %> #%> and <% another tag %>")
27
+ expect(tree).to eq([["a test string with a nested tag: "],
28
+ [[" an iteration tag and "],
29
+ [[" an inner tag "]],
30
+ [" "]],
31
+ [" and "],
32
+ [[" another tag "]]])
33
+ expect(tree[1]).to be_a_kind_of(AdHocTemplate::Parser::IterationTagNode)
34
+ end
35
+ end
36
+
37
+ describe AdHocTemplate::RecordReader do
38
+ it "can read several header type configurations at once." do
39
+ data = <<CONFIGS
40
+
41
+ key1-1: value1-1
42
+ key1-2: value1-2
43
+
44
+ key2-1: value2-1
45
+ key2-2: value2-2
46
+
47
+ key3-1: value3-1
48
+ key3-2: value3-2
49
+
50
+ CONFIGS
51
+
52
+ config = {}
53
+ AdHocTemplate::RecordReader.read_iteration_block(data.each_line.to_a, config, "#configs")
54
+ expect(config).to eq({"#configs"=>[{"key1-1"=>"value1-1", "key1-2"=>"value1-2"},
55
+ {"key2-1"=>"value2-1", "key2-2"=>"value2-2"},
56
+ {"key3-1"=>"value3-1", "key3-2"=>"value3-2"}]})
57
+ end
58
+
59
+ it "reads configuration data and turns them into a hash object" do
60
+ data = <<CONFIG
61
+ key1: value1
62
+ key2: value2
63
+ key3: value3
64
+
65
+ //@block1
66
+
67
+ the first line of block1
68
+ the second line of block1
69
+
70
+ the second paragraph in block1
71
+
72
+ //@block2
73
+ the first line of block2
74
+ the second line of block2
75
+
76
+ the second paragraph of block2
77
+ CONFIG
78
+
79
+ expected_config = {
80
+ "key1" => "value1",
81
+ "key2" => "value2",
82
+ "key3" => "value3",
83
+ "block1" => "the first line of block1\nthe second line of block1\n\nthe second paragraph in block1\n",
84
+ "block2" => "the first line of block2\nthe second line of block2\n\nthe second paragraph of block2\n"
85
+ }
86
+ expect(AdHocTemplate::RecordReader.read_record(data)).to eq(expected_config)
87
+ end
88
+
89
+ it "can read configuration data with 3 different kind of sections" do
90
+ data = <<CONFIG
91
+ key1: value1
92
+ key2: value2
93
+ key3: value3
94
+
95
+ //@#subconfigs
96
+
97
+ key1-1: value1-1
98
+ key1-2: value1-2
99
+
100
+ key2-1: value2-1
101
+ key2-2: value2-2
102
+
103
+ //@block
104
+
105
+ the first line of block
106
+ the second line of block
107
+
108
+ the second paragraph in block
109
+
110
+ CONFIG
111
+
112
+ expected_config = {
113
+ "key1" => "value1",
114
+ "key2" => "value2",
115
+ "key3" => "value3",
116
+ "#subconfigs" => [{"key1-1"=>"value1-1", "key1-2"=>"value1-2"}, {"key2-1"=>"value2-1", "key2-2"=>"value2-2"}],
117
+ "block" => "the first line of block\nthe second line of block\n\nthe second paragraph in block\n"
118
+ }
119
+ expect(AdHocTemplate::RecordReader.read_record(data)).to eq(expected_config)
120
+ end
121
+ end
122
+
123
+ describe AdHocTemplate::Converter do
124
+ it "returns the result of conversion." do
125
+ template = "a test string with tags (<%= key1 %> and <%= key2 %>) in it"
126
+ config_data = <<CONFIG
127
+ key1: value1
128
+ key2: value2
129
+ CONFIG
130
+
131
+ tree = AdHocTemplate::Parser.parse(template)
132
+ config = AdHocTemplate::RecordReader.read_record(config_data)
133
+ expect(AdHocTemplate::Converter.new(config).format(tree)).to eq("a test string with tags (value1 and value2) in it")
134
+ end
135
+
136
+ it "accepts a template with an iteration block and evaluate repeatedly the block" do
137
+ template = <<TEMPLATE
138
+ a test string with tags (<%= key1 %> and <%= key2 %>) in it
139
+
140
+ <%#iteration_block
141
+ the value of sub_key1 is <%= sub_key1 %>
142
+ the value of sub_key2 is <%= sub_key2 %>
143
+
144
+ #%>
145
+ <%= block %>
146
+ TEMPLATE
147
+
148
+ config_data = <<CONFIG
149
+ key1: value1
150
+ key2: value2
151
+ key3: value3
152
+
153
+ //@#iteration_block
154
+
155
+ sub_key1: value1-1
156
+ sub_key2: value1-2
157
+
158
+ sub_key1: value2-1
159
+ sub_key2: value2-2
160
+
161
+ //@block
162
+
163
+ the first line of block
164
+ the second line of block
165
+
166
+ the second paragraph in block
167
+
168
+ CONFIG
169
+
170
+ expected_result = <<RESULT
171
+ a test string with tags (value1 and value2) in it
172
+
173
+ the value of sub_key1 is value1-1
174
+ the value of sub_key2 is value1-2
175
+
176
+ the value of sub_key1 is value2-1
177
+ the value of sub_key2 is value2-2
178
+
179
+
180
+ the first line of block
181
+ the second line of block
182
+
183
+ the second paragraph in block
184
+
185
+ RESULT
186
+ tree = AdHocTemplate::Parser.parse(template)
187
+ config = AdHocTemplate::RecordReader.read_record(config_data)
188
+ expect(AdHocTemplate::Converter.new(config).format(tree)).to eq(expected_result)
189
+ end
190
+
191
+ it "may contains iteration blocks without key label." do
192
+ template = <<TEMPLATE
193
+ a test string with tags (<%= key1 %> and <%= key2 %>) in it
194
+
195
+ <%#
196
+ the value of key1 is <%= key1 %>
197
+ the value of key2 is <%= key2 %>
198
+
199
+ #%>
200
+ <%#
201
+ the value of key2 is <%= non-existent-key %>
202
+ the value of key2 is <%= key-without-value %>
203
+ #%>
204
+ <%# the value of key2 is <%= non-existent-key %> #%>
205
+ <%= block %>
206
+ TEMPLATE
207
+
208
+ config_data = <<CONFIG
209
+ key1: value1
210
+ key2: value2
211
+ key3: value3
212
+ key-without-value:
213
+
214
+ //@block
215
+
216
+ the first line of block
217
+ the second line of block
218
+
219
+ the second paragraph in block
220
+
221
+ CONFIG
222
+
223
+ expected_result = <<RESULT
224
+ a test string with tags (value1 and value2) in it
225
+
226
+ the value of key1 is value1
227
+ the value of key2 is value2
228
+
229
+
230
+
231
+
232
+ the first line of block
233
+ the second line of block
234
+
235
+ the second paragraph in block
236
+
237
+ RESULT
238
+ tree = AdHocTemplate::Parser.parse(template)
239
+ config = AdHocTemplate::RecordReader.read_record(config_data)
240
+ expect(AdHocTemplate::Converter.new(config).format(tree)).to eq(expected_result)
241
+ end
242
+
243
+ it 'can convert &"<> into character entities' do
244
+ result = AdHocTemplate::Converter.convert('characters: &, ", < and >',
245
+ 'a string with characters (<%h characters %>) that should be represented as character entities.')
246
+ expect(result).to eq('a string with characters (&amp;, &quot;, &lt; and &gt;) that should be represented as character entities.')
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'shellwords'
4
+ require 'stringio'
5
+ require 'spec_helper'
6
+ require 'ad_hoc_template'
7
+ require 'ad_hoc_template/command_line_interface'
8
+
9
+ describe AdHocTemplate do
10
+ describe AdHocTemplate::CommandLineInterface do
11
+ it "can set the input/output encoding" do
12
+ command_line_interface = AdHocTemplate::CommandLineInterface.new
13
+ command_line_interface.set_encoding("UTF-8:Shift_JIS")
14
+ expect(command_line_interface.class::Encoding.default_external.names).to include("UTF-8")
15
+ expect(command_line_interface.class::Encoding.default_internal.names).to include("Shift_JIS")
16
+ end
17
+
18
+ it "accepts an internal only argument" do
19
+ command_line_interface = AdHocTemplate::CommandLineInterface.new
20
+ command_line_interface.set_encoding(":UTF-8")
21
+ expect(command_line_interface.class::Encoding.default_internal.names).to include("UTF-8")
22
+ end
23
+
24
+ it "accepts also an external only argument" do
25
+ command_line_interface = AdHocTemplate::CommandLineInterface.new
26
+ command_line_interface.set_encoding("Shift_JIS")
27
+ expect(command_line_interface.class::Encoding.default_external.names).to include("Shift_JIS")
28
+ command_line_interface.set_encoding("UTF-8:")
29
+ expect(command_line_interface.class::Encoding.default_external.names).to include("UTF-8")
30
+ end
31
+
32
+ it "can set the internal/external encoding from the command line" do
33
+ command_line_interface = AdHocTemplate::CommandLineInterface.new
34
+ set_argv("-E UTF-8:Shift_JIS")
35
+ command_line_interface.parse_command_line_options
36
+ expect(command_line_interface.class::Encoding.default_external.names).to include("UTF-8")
37
+ expect(command_line_interface.class::Encoding.default_internal.names).to include("Shift_JIS")
38
+ end
39
+
40
+ it "can specify the output file from command line" do
41
+ pwd = File.expand_path(".")
42
+ output_filename = "file_for_saving_result.txt"
43
+ command_line_interface = AdHocTemplate::CommandLineInterface.new
44
+ set_argv("-o #{output_filename}")
45
+ command_line_interface.parse_command_line_options
46
+ expect(command_line_interface.output_filename).to eq(File.join(pwd, output_filename))
47
+ end
48
+
49
+ it "reads input data from command line" do
50
+ template_filename = "template.txt"
51
+ record_filename = "record.txt"
52
+ template = "a dummy content of template file"
53
+ record = "a dummy content of record file"
54
+
55
+ allow(File).to receive(:read).with(File.expand_path(template_filename)).and_return(template)
56
+ allow(File).to receive(:read).with(File.expand_path(record_filename)).and_return(record)
57
+
58
+ set_argv("#{template_filename} #{record_filename}")
59
+ command_line_interface = AdHocTemplate::CommandLineInterface.new
60
+ command_line_interface.read_input_files
61
+
62
+ expect(command_line_interface.template_data).to eq(template)
63
+ expect(command_line_interface.record_data).to eq(record)
64
+ end
65
+
66
+ it "returns the result to the standard output unless an output file is specified." do
67
+ template_filename = "template.txt"
68
+ record_filename = "record.txt"
69
+
70
+ template = <<TEMPLATE
71
+ a test string with tags (<%= key1 %> and <%= key2 %>) in it
72
+
73
+ <%#iteration_block
74
+ the value of sub_key1 is <%= sub_key1 %>
75
+ the value of sub_key2 is <%= sub_key2 %>
76
+
77
+ #%>
78
+ <%= block %>
79
+ TEMPLATE
80
+
81
+ record = <<CONFIG
82
+ key1: value1
83
+ key2: value2
84
+ key3: value3
85
+
86
+ //@#iteration_block
87
+
88
+ sub_key1: value1-1
89
+ sub_key2: value1-2
90
+
91
+ sub_key1: value2-1
92
+ sub_key2: value2-2
93
+
94
+ //@block
95
+
96
+ the first line of block
97
+ the second line of block
98
+
99
+ the second paragraph in block
100
+
101
+ CONFIG
102
+
103
+ expected_result = <<RESULT
104
+ a test string with tags (value1 and value2) in it
105
+
106
+ the value of sub_key1 is value1-1
107
+ the value of sub_key2 is value1-2
108
+
109
+ the value of sub_key1 is value2-1
110
+ the value of sub_key2 is value2-2
111
+
112
+
113
+ the first line of block
114
+ the second line of block
115
+
116
+ the second paragraph in block
117
+
118
+ RESULT
119
+
120
+
121
+ allow(File).to receive(:read).with(File.expand_path(template_filename)).and_return(template)
122
+ allow(File).to receive(:read).with(File.expand_path(record_filename)).and_return(record)
123
+ allow(STDOUT).to receive(:print).with(expected_result)
124
+
125
+ set_argv("#{template_filename} #{record_filename}")
126
+ command_line_interface = AdHocTemplate::CommandLineInterface.new
127
+ command_line_interface.execute
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'shellwords'
3
+ require 'ad_hoc_template'
4
+
5
+ module Helpers
6
+ def set_argv(command_line_str)
7
+ ARGV.replace Shellwords.split(command_line_str)
8
+ end
9
+ end
10
+
11
+ RSpec.configure do |c|
12
+ c.include Helpers
13
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ad_hoc_template
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - HASHIMOTO, Naoki
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pseudohikiparser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.2'
69
+ description: AdHocTemplate is a template processor with simple but sufficient rules
70
+ for some ad hoc tasks.
71
+ email:
72
+ - hashimoto.naoki@gmail.com
73
+ executables:
74
+ - ad_hoc_template
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".rspec"
80
+ - ".travis.yml"
81
+ - Gemfile
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - ad_hoc_template.gemspec
86
+ - bin/ad_hoc_template
87
+ - lib/ad_hoc_template.rb
88
+ - lib/ad_hoc_template/command_line_interface.rb
89
+ - lib/ad_hoc_template/version.rb
90
+ - spec/ad_hoc_template_spec.rb
91
+ - spec/command_line_interface_spec.rb
92
+ - spec/spec_helper.rb
93
+ homepage: https://github.com/nico-hn/AdHocTemplate
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.2.2
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: A tiny template processor
117
+ test_files:
118
+ - spec/ad_hoc_template_spec.rb
119
+ - spec/command_line_interface_spec.rb
120
+ - spec/spec_helper.rb
121
+ has_rdoc: