ad_hoc_template 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +23 -0
- data/.travis.yml +7 -1
- data/Gemfile +3 -2
- data/ad_hoc_template.gemspec +4 -3
- data/lib/ad_hoc_template.rb +51 -69
- data/lib/ad_hoc_template/command_line_interface.rb +36 -37
- data/lib/ad_hoc_template/config_manager.rb +5 -10
- data/lib/ad_hoc_template/default_tag_formatter.rb +8 -8
- data/lib/ad_hoc_template/entry_format_generator.rb +24 -13
- data/lib/ad_hoc_template/parser.rb +144 -59
- data/lib/ad_hoc_template/pseudohiki_formatter.rb +4 -2
- data/lib/ad_hoc_template/recipe_manager.rb +19 -27
- data/lib/ad_hoc_template/record_reader.rb +59 -56
- data/lib/ad_hoc_template/shim.rb +26 -0
- data/lib/ad_hoc_template/utils.rb +11 -5
- data/lib/ad_hoc_template/version.rb +3 -1
- data/output.html +14 -0
- data/spec/command_line_interface_spec.rb +31 -0
- data/spec/config_manager_spec.rb +4 -4
- data/spec/entry_format_generator_spec.rb +1 -1
- data/spec/parser_spec.rb +15 -1
- data/spec/recipe_manager_spec.rb +14 -14
- metadata +26 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d886560d5c34cfc5a5db65446d0e62b71c70480
|
4
|
+
data.tar.gz: 582cba527d5ecd1e49ff8fb2a1b620c47b58cd02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93aa155f2b7a186c9688bd68d27af013e891f10afe73405d087dea0768cc95d73166a9adbf0c1cb7f301e2988b9357c6c30950f4a2cff24c86a9b78e214a97af
|
7
|
+
data.tar.gz: a91605ac047c69897159b0e20bae32575153f2fcf101a9aeb59ba81775eb740024e2bf4486055035d7346bb175c3b8f30edbab044c929732f525e92754f5249b
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.3
|
3
|
+
Layout/SpaceInsideBlockBraces:
|
4
|
+
SpaceBeforeBlockParameters: false
|
5
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
6
|
+
EnforcedStyle: no_space
|
7
|
+
Layout/MultilineMethodCallIndentation:
|
8
|
+
EnforcedStyle: indented_relative_to_receiver
|
9
|
+
Style/ClassCheck:
|
10
|
+
EnforcedStyle: kind_of?
|
11
|
+
Style/TrailingCommaInArrayLiteral:
|
12
|
+
EnforcedStyleForMultiline: consistent_comma
|
13
|
+
Style/TrailingCommaInHashLiteral:
|
14
|
+
EnforcedStyleForMultiline: consistent_comma
|
15
|
+
Style/SpecialGlobalVars:
|
16
|
+
EnforcedStyle: use_perl_names
|
17
|
+
Documentation:
|
18
|
+
Enabled: false
|
19
|
+
Style/ParallelAssignment:
|
20
|
+
Enabled: false
|
21
|
+
Style/FrozenStringLiteralComment:
|
22
|
+
Enabled: true
|
23
|
+
EnforcedStyle: always
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -2,11 +2,12 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in ad_hoc_template.gemspec
|
4
4
|
|
5
|
-
gem 'pseudohikiparser', '0.0.
|
5
|
+
gem 'pseudohikiparser', '0.0.6.develop'
|
6
6
|
gem 'optparse_plus'
|
7
7
|
|
8
8
|
group :development do
|
9
|
-
gem "bundler", "~> 1.
|
9
|
+
gem "bundler", "~> 1.16"
|
10
10
|
gem "rake"
|
11
11
|
gem "rspec"
|
12
|
+
gem "rubocop", "~> 0.55"
|
12
13
|
end
|
data/ad_hoc_template.gemspec
CHANGED
@@ -20,7 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.add_runtime_dependency "pseudohikiparser", "0.0.6.develop"
|
21
21
|
spec.add_runtime_dependency "optparse_plus"
|
22
22
|
|
23
|
-
spec.add_development_dependency "bundler", "~> 1.
|
24
|
-
spec.add_development_dependency "rake", "~>
|
25
|
-
spec.add_development_dependency "rspec", "~> 3.
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
24
|
+
spec.add_development_dependency "rake", "~> 12.3"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.7"
|
26
|
+
spec.add_development_dependency "rubocop", "~> 0.55"
|
26
27
|
end
|
data/lib/ad_hoc_template.rb
CHANGED
@@ -1,31 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ad_hoc_template/version'
|
4
|
+
require 'ad_hoc_template/parser'
|
5
|
+
require 'ad_hoc_template/record_reader'
|
6
|
+
require 'ad_hoc_template/default_tag_formatter'
|
7
|
+
require 'ad_hoc_template/pseudohiki_formatter'
|
8
|
+
require 'ad_hoc_template/entry_format_generator'
|
9
|
+
require 'ad_hoc_template/config_manager'
|
8
10
|
|
9
11
|
module AdHocTemplate
|
10
12
|
class DataLoader
|
11
|
-
class InnerLabel
|
12
|
-
attr_reader :inner_label
|
13
|
-
|
14
|
-
def self.labels(inner_labels, cur_label)
|
15
|
-
inner_labels.map {|label| new(label, cur_label) }
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize(inner_label, cur_label)
|
19
|
-
@inner_label = inner_label
|
20
|
-
@label, @key = inner_label.sub(/\A#/, ''.freeze).split(/\|/, 2)
|
21
|
-
@cur_label = cur_label
|
22
|
-
end
|
23
|
-
|
24
|
-
def full_label(record)
|
25
|
-
[@cur_label, @label, record[@key]].join('|')
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
13
|
def self.format(template, record, tag_formatter=DefaultTagFormatter.new)
|
30
14
|
if record.kind_of? Array
|
31
15
|
return format_multi_records(template, record, tag_formatter)
|
@@ -40,6 +24,8 @@ module AdHocTemplate
|
|
40
24
|
end.join
|
41
25
|
end
|
42
26
|
|
27
|
+
attr_reader :record, :tag_formatter
|
28
|
+
|
43
29
|
def initialize(record, tag_formatter=DefaultTagFormatter.new)
|
44
30
|
@record = record
|
45
31
|
@tag_formatter = tag_formatter
|
@@ -48,11 +34,11 @@ module AdHocTemplate
|
|
48
34
|
def visit(tree, memo)
|
49
35
|
case tree
|
50
36
|
when Parser::IterationNode
|
51
|
-
format_iteration_tag(tree, memo)
|
37
|
+
format_iteration_tag(tree, self, memo)
|
52
38
|
when Parser::FallbackNode
|
53
|
-
''
|
39
|
+
''
|
54
40
|
when Parser::ValueNode
|
55
|
-
format_value_tag(tree, memo)
|
41
|
+
format_value_tag(tree, self, memo)
|
56
42
|
when Parser::Leaf
|
57
43
|
tree.join
|
58
44
|
else
|
@@ -60,51 +46,48 @@ module AdHocTemplate
|
|
60
46
|
end
|
61
47
|
end
|
62
48
|
|
63
|
-
def format_iteration_tag(iteration_tag_node, memo)
|
64
|
-
tag_node = cast
|
49
|
+
def format_iteration_tag(iteration_tag_node, data_loader, memo)
|
50
|
+
tag_node = iteration_tag_node.cast
|
65
51
|
|
66
|
-
prepare_sub_records(iteration_tag_node).map do |record|
|
67
|
-
|
68
|
-
visit_with_sub_record(tag_node, record, memo)
|
69
|
-
elsif fallback_nodes = select_fallback_nodes(tag_node)
|
70
|
-
format_fallback_tags(fallback_nodes, record, memo)
|
71
|
-
else
|
72
|
-
"".freeze
|
73
|
-
end
|
52
|
+
prepare_sub_records(iteration_tag_node, data_loader).map do |record|
|
53
|
+
format_sub_nodes(tag_node, record, data_loader, memo)
|
74
54
|
end
|
75
55
|
end
|
76
56
|
|
77
|
-
def format_value_tag(tag_node, memo)
|
78
|
-
leafs = tag_node.
|
79
|
-
|
57
|
+
def format_value_tag(tag_node, data_loader, memo)
|
58
|
+
leafs = tag_node.format_sub_nodes(data_loader, memo).strip
|
59
|
+
data_loader.tag_formatter.format(tag_node.type, leafs, data_loader.record)
|
80
60
|
end
|
81
61
|
|
82
62
|
def format(tree, memo=nil)
|
83
63
|
tree.accept(self, memo).join
|
84
64
|
end
|
85
65
|
|
86
|
-
|
66
|
+
def new_with_record(record)
|
67
|
+
self.class.new(record, @tag_formatter)
|
68
|
+
end
|
87
69
|
|
88
|
-
|
89
|
-
|
70
|
+
protected
|
71
|
+
|
72
|
+
def sub_records(tag_node)
|
73
|
+
@record[tag_node.type] || [@record]
|
90
74
|
end
|
91
75
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
sub_records.map do |record|
|
100
|
-
prepare_inner_iteration_records(record, inner_labels)
|
76
|
+
private
|
77
|
+
|
78
|
+
def prepare_sub_records(tag_node, data_loader)
|
79
|
+
inner_labels = tag_node.inner_labels
|
80
|
+
return data_loader.sub_records(tag_node) unless inner_labels
|
81
|
+
data_loader.sub_records(tag_node).map do |record|
|
82
|
+
merge_inner_iteration_records(record, inner_labels, data_loader)
|
101
83
|
end
|
102
84
|
end
|
103
85
|
|
104
|
-
def
|
86
|
+
def merge_inner_iteration_records(record, inner_labels, data_loader)
|
105
87
|
new_record = nil
|
106
88
|
inner_labels.each do |label|
|
107
|
-
|
89
|
+
inner_data = data_loader.record[label.full_label(record)]
|
90
|
+
if inner_data
|
108
91
|
new_record ||= record.dup
|
109
92
|
new_record[label.inner_label] = inner_data
|
110
93
|
end
|
@@ -112,27 +95,26 @@ module AdHocTemplate
|
|
112
95
|
new_record || record
|
113
96
|
end
|
114
97
|
|
115
|
-
def
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
98
|
+
def format_sub_nodes(tag_node, record, data_loader, memo)
|
99
|
+
if tag_node.contains_any_value_assigned_tag_node?(record)
|
100
|
+
tag_node.format_sub_nodes(data_loader.new_with_record(record), memo)
|
101
|
+
elsif tag_node.contains_any_fallback_tag?
|
102
|
+
format_fallback_tags(tag_node.select_fallback_nodes,
|
103
|
+
data_loader.new_with_record(record), memo)
|
104
|
+
else
|
105
|
+
''
|
106
|
+
end
|
123
107
|
end
|
124
108
|
|
125
|
-
def format_fallback_tags(fallback_nodes,
|
126
|
-
data_loader = AdHocTemplate::DataLoader.new(record, @tag_formatter)
|
109
|
+
def format_fallback_tags(fallback_nodes, data_loader, memo)
|
127
110
|
fallback_nodes.map do |fallback_node|
|
128
|
-
|
129
|
-
node.contains_any_value_tag? ? node.accept(data_loader, memo) : node.join
|
111
|
+
fallback_node.format_sub_nodes(data_loader, memo)
|
130
112
|
end
|
131
113
|
end
|
132
114
|
end
|
133
115
|
|
134
|
-
def self.render(record_data, template, tag_type=:default,
|
135
|
-
tag_formatter=DefaultTagFormatter.new)
|
116
|
+
def self.render(record_data, template, tag_type=:default,
|
117
|
+
data_format=:default, tag_formatter=DefaultTagFormatter.new)
|
136
118
|
tree = Parser.parse(template, tag_type)
|
137
119
|
record = RecordReader.read_record(record_data, data_format)
|
138
120
|
DataLoader.format(tree, record, tag_formatter)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'ad_hoc_template'
|
4
4
|
require 'optparse_plus'
|
@@ -11,7 +11,8 @@ AdHocTemplate::ConfigManager.require_local_settings
|
|
11
11
|
module AdHocTemplate
|
12
12
|
class CommandLineInterface
|
13
13
|
include Utils
|
14
|
-
attr_accessor :output_filename, :
|
14
|
+
attr_accessor :output_filename, :tag_type, :data_format,
|
15
|
+
:template_data, :record_data
|
15
16
|
attr_writer :output_empty_entry
|
16
17
|
|
17
18
|
TAG_RE_TO_TYPE = {
|
@@ -21,15 +22,15 @@ module AdHocTemplate
|
|
21
22
|
/\Axml_like1/i => :xml_like1,
|
22
23
|
/\Axml_like2/i => :xml_like2,
|
23
24
|
/\Axml_comment_like/i => :xml_comment_like,
|
24
|
-
}
|
25
|
+
}.freeze
|
25
26
|
|
26
|
-
|
27
|
+
RE_TO_FORMAT = {
|
27
28
|
/\Ad(efault)?/i => :default,
|
28
29
|
/\Ay(a?ml)?/i => :yaml,
|
29
30
|
/\Aj(son)?/i => :json,
|
30
31
|
/\Ac(sv)?/i => :csv,
|
31
32
|
/\At(sv)?/i => :tsv,
|
32
|
-
}
|
33
|
+
}.freeze
|
33
34
|
|
34
35
|
def initialize
|
35
36
|
@tag_formatter = AdHocTemplate::DefaultTagFormatter.new
|
@@ -37,6 +38,7 @@ module AdHocTemplate
|
|
37
38
|
@tag_type = :default
|
38
39
|
@data_format = nil
|
39
40
|
@force_update = false
|
41
|
+
@init_local_settings = false
|
40
42
|
end
|
41
43
|
|
42
44
|
def parse_command_line_options
|
@@ -45,11 +47,11 @@ module AdHocTemplate
|
|
45
47
|
opt.version = AdHocTemplate::VERSION
|
46
48
|
|
47
49
|
opt.inherit_ruby_options('E') # -E, --encoding
|
48
|
-
opt.on(:output_file) {|
|
50
|
+
opt.on(:output_file) {|file| @output_filename = File.expand_path(file) }
|
49
51
|
opt.on(:tag_type) {|given_type| choose_tag_type(given_type) }
|
50
52
|
opt.on(:data_format) {|data_format| choose_data_format(data_format) }
|
51
|
-
opt.on(:tag_config) {|
|
52
|
-
opt.on(:entry_format) {
|
53
|
+
opt.on(:tag_config) {|yaml| register_user_defined_tag_type(yaml) }
|
54
|
+
opt.on(:entry_format) { @output_empty_entry = true }
|
53
55
|
opt.on(:init_local_settings) { init_local_settings }
|
54
56
|
opt.on(:recipe_template) { @output_recipe_template = true }
|
55
57
|
opt.on(:cooking_recipe) {|recipe_yaml| @recipe_yaml = recipe_yaml }
|
@@ -60,7 +62,7 @@ module AdHocTemplate
|
|
60
62
|
|
61
63
|
unless @data_format
|
62
64
|
guessed_format = ARGV.length < 2 ? :default : guess_file_format(ARGV[1])
|
63
|
-
@data_format =
|
65
|
+
@data_format = guessed_format || :default
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
@@ -69,7 +71,7 @@ module AdHocTemplate
|
|
69
71
|
if template
|
70
72
|
@template_data = File.read(template)
|
71
73
|
else
|
72
|
-
STDERR.puts
|
74
|
+
STDERR.puts 'No template file is given.'
|
73
75
|
end
|
74
76
|
|
75
77
|
@record_data = record ? File.read(record) : ARGF.read
|
@@ -77,7 +79,7 @@ module AdHocTemplate
|
|
77
79
|
|
78
80
|
def render
|
79
81
|
AdHocTemplate.render(@record_data, @template_data, @tag_type,
|
80
|
-
|
82
|
+
@data_format, @tag_formatter)
|
81
83
|
end
|
82
84
|
|
83
85
|
def generate_entry_format
|
@@ -87,28 +89,25 @@ module AdHocTemplate
|
|
87
89
|
|
88
90
|
def init_local_settings
|
89
91
|
AdHocTemplate::ConfigManager.init_local_settings
|
90
|
-
config_dir =
|
92
|
+
config_dir = ConfigManager.expand_path('')
|
91
93
|
puts "Please edit configuration files created in #{config_dir}"
|
92
|
-
|
94
|
+
@init_local_settings = true
|
93
95
|
end
|
94
96
|
|
95
97
|
def generate_recipe_template(templates)
|
96
98
|
encoding = Encoding.default_external.names[0]
|
97
|
-
AdHocTemplate::EntryFormatGenerator
|
98
|
-
extract_recipes_from_template_files(templates,
|
99
|
-
@tag_type)
|
99
|
+
AdHocTemplate::EntryFormatGenerator
|
100
|
+
.extract_recipes_from_template_files(templates, @tag_type, encoding)
|
100
101
|
end
|
101
102
|
|
102
103
|
def update_output_files_in_recipe(recipe)
|
103
|
-
AdHocTemplate::RecipeManager
|
104
|
-
|
104
|
+
AdHocTemplate::RecipeManager
|
105
|
+
.update_output_files_in_recipe(recipe, @force_update)
|
105
106
|
end
|
106
107
|
|
107
108
|
def open_output
|
108
109
|
if @output_filename
|
109
|
-
open(@output_filename,
|
110
|
-
yield out
|
111
|
-
end
|
110
|
+
File.open(@output_filename, 'wb') {|out| yield out }
|
112
111
|
else
|
113
112
|
yield STDOUT
|
114
113
|
end
|
@@ -116,34 +115,35 @@ module AdHocTemplate
|
|
116
115
|
|
117
116
|
def execute
|
118
117
|
parse_command_line_options
|
118
|
+
exit if @init_local_settings
|
119
119
|
return update_output_files_in_recipe(@recipe_yaml) if @recipe_yaml
|
120
120
|
read_input_files
|
121
|
-
|
122
|
-
generate_entry_format
|
123
|
-
elsif @output_recipe_template
|
124
|
-
generate_recipe_template(ARGV)
|
125
|
-
else
|
126
|
-
render
|
127
|
-
end
|
128
|
-
open_output {|out| out.print output }
|
121
|
+
open_output {|out| out.print generate_output }
|
129
122
|
end
|
130
123
|
|
131
124
|
private
|
132
125
|
|
126
|
+
def generate_output
|
127
|
+
return generate_entry_format if @output_empty_entry
|
128
|
+
return generate_recipe_template(ARGV) if @output_recipe_template
|
129
|
+
render
|
130
|
+
end
|
131
|
+
|
133
132
|
def choose_tag_type(given_type)
|
134
|
-
err_msg =
|
133
|
+
err_msg = 'The given type is not found. The default tag is chosen.'
|
135
134
|
|
136
|
-
if_any_regex_match(TAG_RE_TO_TYPE, given_type, err_msg) do |
|
135
|
+
if_any_regex_match(TAG_RE_TO_TYPE, given_type, err_msg) do |_, tag_type|
|
137
136
|
@tag_type = tag_type
|
138
137
|
end
|
139
138
|
end
|
140
139
|
|
141
140
|
def choose_data_format(data_format)
|
142
|
-
err_msg =
|
141
|
+
err_msg = 'The given format is not found. The default format is chosen.'
|
143
142
|
format_part, label_part = data_format.split(/:/, 2)
|
144
143
|
|
145
|
-
if_any_regex_match(
|
146
|
-
|
144
|
+
if_any_regex_match(RE_TO_FORMAT, format_part, err_msg) do |_, format|
|
145
|
+
csv_with_label = value_assigned?(label_part) && csv_or_tsv?(format)
|
146
|
+
@data_format = csv_with_label ? { format => label_part } : format
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
@@ -152,9 +152,8 @@ module AdHocTemplate
|
|
152
152
|
@tag_type = Parser.register_user_defined_tag_type(config)
|
153
153
|
end
|
154
154
|
|
155
|
-
def
|
156
|
-
|
157
|
-
{ format => iteration_label }
|
155
|
+
def value_assigned?(iteration_label)
|
156
|
+
!(iteration_label.nil? || iteration_label.empty?)
|
158
157
|
end
|
159
158
|
end
|
160
159
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
4
|
|
@@ -12,9 +12,7 @@ module AdHocTemplate
|
|
12
12
|
|
13
13
|
def self.require_local_settings
|
14
14
|
settings_file = File.expand_path(LOCAL_SETTINGS_FILE)
|
15
|
-
if File.exist? settings_file
|
16
|
-
require settings_file
|
17
|
-
end
|
15
|
+
require settings_file if File.exist? settings_file
|
18
16
|
end
|
19
17
|
|
20
18
|
def self.configure(&config_block)
|
@@ -44,18 +42,15 @@ module AdHocTemplate
|
|
44
42
|
end
|
45
43
|
|
46
44
|
def self.expand_path(path)
|
47
|
-
unless
|
48
|
-
path = File.join(LOCAL_SETTINGS_DIR, path)
|
49
|
-
end
|
45
|
+
path = File.join(LOCAL_SETTINGS_DIR, path) unless %r{\A[\./]} =~ path
|
50
46
|
File.expand_path(path)
|
51
47
|
end
|
52
48
|
|
53
49
|
def self.create_unless_exist(path, content)
|
54
50
|
return if File.exist? path
|
55
|
-
open(path,
|
51
|
+
File.open(path, 'wb') {|file| file.print content }
|
56
52
|
end
|
57
53
|
|
58
|
-
private_class_method :expand_path
|
59
54
|
private_class_method :create_unless_exist
|
60
55
|
|
61
56
|
@local_settings_template = <<SETTING_TEMPLATE
|
@@ -117,7 +112,7 @@ AdHocTemplate.local_settings do
|
|
117
112
|
end
|
118
113
|
SETTING_TEMPLATE
|
119
114
|
|
120
|
-
@custom_tag_template
|
115
|
+
@custom_tag_template = <<TAG_TEMPLATE
|
121
116
|
---
|
122
117
|
tag_name: :default
|
123
118
|
tag: ["<%", "%>"]
|