ad_hoc_template 0.4.0 → 0.4.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.
- 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: ["<%", "%>"]
|