htot_conv 0.3.2 → 1.0.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.
- checksums.yaml +4 -4
- data/.gitignore +135 -135
- data/.travis.yml +12 -12
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +46 -138
- data/Rakefile +10 -10
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/docs/image/output_xlsx_type0.png +0 -0
- data/docs/image/output_xlsx_type1.png +0 -0
- data/docs/image/output_xlsx_type1_outline_rows_yes.png +0 -0
- data/docs/image/output_xlsx_type2.png +0 -0
- data/docs/image/output_xlsx_type2_integrate_cells_colspan.png +0 -0
- data/docs/image/output_xlsx_type2_outline_rows_yes.png +0 -0
- data/docs/image/output_xlsx_type3.png +0 -0
- data/docs/image/output_xlsx_type3_integrate_cells_both.png +0 -0
- data/docs/image/output_xlsx_type4.png +0 -0
- data/docs/image/output_xlsx_type4_integrate_cells_both.png +0 -0
- data/docs/image/output_xlsx_type5.png +0 -0
- data/docs/image/output_xlsx_type5_integrate_cells_colspan.png +0 -0
- data/docs/index.md +88 -0
- data/exe/htot_conv +8 -8
- data/htot_conv.gemspec +37 -37
- data/lib/htot_conv.rb +20 -20
- data/lib/htot_conv/cli.rb +174 -174
- data/lib/htot_conv/generator.rb +30 -30
- data/lib/htot_conv/generator/base.rb +34 -35
- data/lib/htot_conv/generator/xlsx_type0.rb +36 -24
- data/lib/htot_conv/generator/xlsx_type1.rb +57 -69
- data/lib/htot_conv/generator/xlsx_type2.rb +100 -104
- data/lib/htot_conv/generator/xlsx_type3.rb +99 -85
- data/lib/htot_conv/generator/xlsx_type4.rb +109 -84
- data/lib/htot_conv/generator/xlsx_type5.rb +75 -62
- data/lib/htot_conv/outline.rb +176 -176
- data/lib/htot_conv/parser.rb +27 -27
- data/lib/htot_conv/parser/base.rb +15 -15
- data/lib/htot_conv/parser/dir_tree.rb +54 -54
- data/lib/htot_conv/parser/html_list.rb +71 -71
- data/lib/htot_conv/parser/opml.rb +70 -70
- data/lib/htot_conv/parser/simple_text.rb +70 -70
- data/lib/htot_conv/util.rb +13 -13
- data/lib/htot_conv/version.rb +4 -4
- metadata +19 -6
data/lib/htot_conv/outline.rb
CHANGED
@@ -1,176 +1,176 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module HTOTConv
|
3
|
-
class Outline
|
4
|
-
def initialize
|
5
|
-
@item = []
|
6
|
-
end
|
7
|
-
|
8
|
-
attr_accessor :key_header
|
9
|
-
attr_accessor :value_header
|
10
|
-
attr_accessor :item
|
11
|
-
|
12
|
-
def add_item(*args)
|
13
|
-
@item << Item.new(*args)
|
14
|
-
end
|
15
|
-
|
16
|
-
def validate
|
17
|
-
raise ValidationError, "key_header must be an array" unless @key_header.kind_of?(Array)
|
18
|
-
raise ValidationError, "key_header elements must be strings." unless @key_header.all? { |v| v.nil? || v.kind_of?(String) }
|
19
|
-
raise ValidationError, "value_header must be an array" unless @value_header.kind_of?(Array)
|
20
|
-
raise ValidationError, "value_header elements must be strings." unless @value_header.all? { |v| v.nil? || v.kind_of?(String) }
|
21
|
-
raise ValidationError, "item must be an array" unless @item.kind_of?(Array)
|
22
|
-
@item.each { |item| item.validate }
|
23
|
-
end
|
24
|
-
|
25
|
-
def valid?
|
26
|
-
begin
|
27
|
-
validate
|
28
|
-
true
|
29
|
-
rescue ValidationError
|
30
|
-
false
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def max_level
|
35
|
-
[
|
36
|
-
@key_header.length,
|
37
|
-
*(@item.map { |v| v.level.to_i }),
|
38
|
-
].max
|
39
|
-
end
|
40
|
-
|
41
|
-
def max_value_length
|
42
|
-
[
|
43
|
-
@value_header.length,
|
44
|
-
*(@item.map { |v| (v.value)? v.value.length : 0 }),
|
45
|
-
].max
|
46
|
-
end
|
47
|
-
|
48
|
-
def ==(v)
|
49
|
-
(@key_header == v.key_header) &&
|
50
|
-
(@value_header == v.value_header) &&
|
51
|
-
(@item == v.item)
|
52
|
-
end
|
53
|
-
|
54
|
-
def to_tree
|
55
|
-
root = Tree.new
|
56
|
-
last_node = root
|
57
|
-
@item.each_with_index do |item,i|
|
58
|
-
parent_node = root
|
59
|
-
if ((item.level > 1) && !(last_node.root?))
|
60
|
-
if item.level > last_node.item.level
|
61
|
-
parent_node = last_node
|
62
|
-
else
|
63
|
-
parent_node = last_node.parent
|
64
|
-
parent_node = parent_node.parent until (parent_node.root? || parent_node.item.level < item.level)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
parent_node << item
|
69
|
-
last_node = parent_node.to_a.last
|
70
|
-
end
|
71
|
-
root
|
72
|
-
end
|
73
|
-
|
74
|
-
class ValidationError < RuntimeError
|
75
|
-
end
|
76
|
-
|
77
|
-
Item = Struct.new(:key, :level, :value) do
|
78
|
-
def validate
|
79
|
-
raise ValidationError, "item level for item \"#{key}\" must be an integer" unless self.level.kind_of?(Numeric)
|
80
|
-
raise ValidationError, "item level for item \"#{key}\" must be positive" unless self.level > 0
|
81
|
-
raise ValidationError, "item level for item \"#{key}\" must be an integer" unless (self.level.to_i == self.level)
|
82
|
-
raise ValidationError, "value for item \"#{key}\" must be an array" unless self.value.kind_of?(Array)
|
83
|
-
end
|
84
|
-
|
85
|
-
def valid?
|
86
|
-
begin
|
87
|
-
validate
|
88
|
-
true
|
89
|
-
rescue ValidationError
|
90
|
-
false
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
class Tree
|
96
|
-
include Enumerable
|
97
|
-
|
98
|
-
def initialize(item=nil, parent=nil)
|
99
|
-
@item = item
|
100
|
-
@parent = parent
|
101
|
-
@children = []
|
102
|
-
end
|
103
|
-
attr_accessor :item
|
104
|
-
attr_reader :parent
|
105
|
-
|
106
|
-
def root?
|
107
|
-
@parent.nil?
|
108
|
-
end
|
109
|
-
|
110
|
-
def leaf?
|
111
|
-
@children.empty?
|
112
|
-
end
|
113
|
-
|
114
|
-
def add(item)
|
115
|
-
child = Tree.new(item, self)
|
116
|
-
@children << child
|
117
|
-
self
|
118
|
-
end
|
119
|
-
alias :<< :add
|
120
|
-
|
121
|
-
def each # :yield: child
|
122
|
-
@children.each do |v|
|
123
|
-
yield v if block_given?
|
124
|
-
end
|
125
|
-
@children.dup
|
126
|
-
end
|
127
|
-
|
128
|
-
def root
|
129
|
-
node = self
|
130
|
-
node = node.parent until node.root?
|
131
|
-
node
|
132
|
-
end
|
133
|
-
|
134
|
-
def next
|
135
|
-
if root?
|
136
|
-
nil
|
137
|
-
else
|
138
|
-
brothers = parent.to_a
|
139
|
-
index = brothers.index(self)
|
140
|
-
(index + 1 < brothers.length)? brothers[index + 1] : nil
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def prev
|
145
|
-
if root?
|
146
|
-
nil
|
147
|
-
else
|
148
|
-
brothers = parent.to_a
|
149
|
-
index = brothers.index(self)
|
150
|
-
(index - 1 >= 0)? brothers[index - 1] : nil
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def ancestors
|
155
|
-
Enumerator.new do |y|
|
156
|
-
node = self.parent
|
157
|
-
until (node.nil? || node.root?)
|
158
|
-
y << node
|
159
|
-
node = node.parent
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def descendants
|
165
|
-
Enumerator.new do |y|
|
166
|
-
@children.each do |child|
|
167
|
-
y << child
|
168
|
-
child.descendants.each do |descendant|
|
169
|
-
y << descendant
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module HTOTConv
|
3
|
+
class Outline
|
4
|
+
def initialize
|
5
|
+
@item = []
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_accessor :key_header
|
9
|
+
attr_accessor :value_header
|
10
|
+
attr_accessor :item
|
11
|
+
|
12
|
+
def add_item(*args)
|
13
|
+
@item << Item.new(*args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate
|
17
|
+
raise ValidationError, "key_header must be an array" unless @key_header.kind_of?(Array)
|
18
|
+
raise ValidationError, "key_header elements must be strings." unless @key_header.all? { |v| v.nil? || v.kind_of?(String) }
|
19
|
+
raise ValidationError, "value_header must be an array" unless @value_header.kind_of?(Array)
|
20
|
+
raise ValidationError, "value_header elements must be strings." unless @value_header.all? { |v| v.nil? || v.kind_of?(String) }
|
21
|
+
raise ValidationError, "item must be an array" unless @item.kind_of?(Array)
|
22
|
+
@item.each { |item| item.validate }
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid?
|
26
|
+
begin
|
27
|
+
validate
|
28
|
+
true
|
29
|
+
rescue ValidationError
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def max_level
|
35
|
+
[
|
36
|
+
@key_header.length,
|
37
|
+
*(@item.map { |v| v.level.to_i }),
|
38
|
+
].max
|
39
|
+
end
|
40
|
+
|
41
|
+
def max_value_length
|
42
|
+
[
|
43
|
+
@value_header.length,
|
44
|
+
*(@item.map { |v| (v.value)? v.value.length : 0 }),
|
45
|
+
].max
|
46
|
+
end
|
47
|
+
|
48
|
+
def ==(v)
|
49
|
+
(@key_header == v.key_header) &&
|
50
|
+
(@value_header == v.value_header) &&
|
51
|
+
(@item == v.item)
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_tree
|
55
|
+
root = Tree.new
|
56
|
+
last_node = root
|
57
|
+
@item.each_with_index do |item,i|
|
58
|
+
parent_node = root
|
59
|
+
if ((item.level > 1) && !(last_node.root?))
|
60
|
+
if item.level > last_node.item.level
|
61
|
+
parent_node = last_node
|
62
|
+
else
|
63
|
+
parent_node = last_node.parent
|
64
|
+
parent_node = parent_node.parent until (parent_node.root? || parent_node.item.level < item.level)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
parent_node << item
|
69
|
+
last_node = parent_node.to_a.last
|
70
|
+
end
|
71
|
+
root
|
72
|
+
end
|
73
|
+
|
74
|
+
class ValidationError < RuntimeError
|
75
|
+
end
|
76
|
+
|
77
|
+
Item = Struct.new(:key, :level, :value) do
|
78
|
+
def validate
|
79
|
+
raise ValidationError, "item level for item \"#{key}\" must be an integer" unless self.level.kind_of?(Numeric)
|
80
|
+
raise ValidationError, "item level for item \"#{key}\" must be positive" unless self.level > 0
|
81
|
+
raise ValidationError, "item level for item \"#{key}\" must be an integer" unless (self.level.to_i == self.level)
|
82
|
+
raise ValidationError, "value for item \"#{key}\" must be an array" unless self.value.kind_of?(Array)
|
83
|
+
end
|
84
|
+
|
85
|
+
def valid?
|
86
|
+
begin
|
87
|
+
validate
|
88
|
+
true
|
89
|
+
rescue ValidationError
|
90
|
+
false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Tree
|
96
|
+
include Enumerable
|
97
|
+
|
98
|
+
def initialize(item=nil, parent=nil)
|
99
|
+
@item = item
|
100
|
+
@parent = parent
|
101
|
+
@children = []
|
102
|
+
end
|
103
|
+
attr_accessor :item
|
104
|
+
attr_reader :parent
|
105
|
+
|
106
|
+
def root?
|
107
|
+
@parent.nil?
|
108
|
+
end
|
109
|
+
|
110
|
+
def leaf?
|
111
|
+
@children.empty?
|
112
|
+
end
|
113
|
+
|
114
|
+
def add(item)
|
115
|
+
child = Tree.new(item, self)
|
116
|
+
@children << child
|
117
|
+
self
|
118
|
+
end
|
119
|
+
alias :<< :add
|
120
|
+
|
121
|
+
def each # :yield: child
|
122
|
+
@children.each do |v|
|
123
|
+
yield v if block_given?
|
124
|
+
end
|
125
|
+
@children.dup
|
126
|
+
end
|
127
|
+
|
128
|
+
def root
|
129
|
+
node = self
|
130
|
+
node = node.parent until node.root?
|
131
|
+
node
|
132
|
+
end
|
133
|
+
|
134
|
+
def next
|
135
|
+
if root?
|
136
|
+
nil
|
137
|
+
else
|
138
|
+
brothers = parent.to_a
|
139
|
+
index = brothers.index(self)
|
140
|
+
(index + 1 < brothers.length)? brothers[index + 1] : nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def prev
|
145
|
+
if root?
|
146
|
+
nil
|
147
|
+
else
|
148
|
+
brothers = parent.to_a
|
149
|
+
index = brothers.index(self)
|
150
|
+
(index - 1 >= 0)? brothers[index - 1] : nil
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def ancestors
|
155
|
+
Enumerator.new do |y|
|
156
|
+
node = self.parent
|
157
|
+
until (node.nil? || node.root?)
|
158
|
+
y << node
|
159
|
+
node = node.parent
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def descendants
|
165
|
+
Enumerator.new do |y|
|
166
|
+
@children.each do |child|
|
167
|
+
y << child
|
168
|
+
child.descendants.each do |descendant|
|
169
|
+
y << descendant
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
data/lib/htot_conv/parser.rb
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'htot_conv/parser/base.rb'
|
3
|
-
require 'htot_conv/parser/simple_text.rb'
|
4
|
-
require 'htot_conv/parser/dir_tree.rb'
|
5
|
-
require 'htot_conv/parser/html_list.rb'
|
6
|
-
require 'htot_conv/parser/opml.rb'
|
7
|
-
|
8
|
-
module HTOTConv
|
9
|
-
module Parser
|
10
|
-
def create(type, *args)
|
11
|
-
klass = HTOTConv::Parser.const_get(Rinne.camelize(type.to_s))
|
12
|
-
klass.new(*args)
|
13
|
-
end
|
14
|
-
module_function :create
|
15
|
-
|
16
|
-
def types
|
17
|
-
HTOTConv::Parser.constants.reject { |klass|
|
18
|
-
klass =~ /Base$/
|
19
|
-
}.select { |klass|
|
20
|
-
HTOTConv::Parser.const_get(klass).kind_of?(Class)
|
21
|
-
}.map { |klass|
|
22
|
-
Rinne.to_snake(klass.to_s).to_sym
|
23
|
-
}
|
24
|
-
end
|
25
|
-
module_function :types
|
26
|
-
end
|
27
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'htot_conv/parser/base.rb'
|
3
|
+
require 'htot_conv/parser/simple_text.rb'
|
4
|
+
require 'htot_conv/parser/dir_tree.rb'
|
5
|
+
require 'htot_conv/parser/html_list.rb'
|
6
|
+
require 'htot_conv/parser/opml.rb'
|
7
|
+
|
8
|
+
module HTOTConv
|
9
|
+
module Parser
|
10
|
+
def create(type, *args)
|
11
|
+
klass = HTOTConv::Parser.const_get(Rinne.camelize(type.to_s))
|
12
|
+
klass.new(*args)
|
13
|
+
end
|
14
|
+
module_function :create
|
15
|
+
|
16
|
+
def types
|
17
|
+
HTOTConv::Parser.constants.reject { |klass|
|
18
|
+
klass =~ /Base$/
|
19
|
+
}.select { |klass|
|
20
|
+
HTOTConv::Parser.const_get(klass).kind_of?(Class)
|
21
|
+
}.map { |klass|
|
22
|
+
Rinne.to_snake(klass.to_s).to_sym
|
23
|
+
}
|
24
|
+
end
|
25
|
+
module_function :types
|
26
|
+
end
|
27
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module HTOTConv
|
3
|
-
module Parser
|
4
|
-
class Base
|
5
|
-
def initialize(option={})
|
6
|
-
@option = self.class.option_help.inject({}) { |h, pair| h[pair[0]] = pair[1][:default]; h}.merge(option)
|
7
|
-
end
|
8
|
-
attr_accessor :option
|
9
|
-
|
10
|
-
def self.option_help
|
11
|
-
{}
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module HTOTConv
|
3
|
+
module Parser
|
4
|
+
class Base
|
5
|
+
def initialize(option={})
|
6
|
+
@option = self.class.option_help.inject({}) { |h, pair| h[pair[0]] = pair[1][:default]; h}.merge(option)
|
7
|
+
end
|
8
|
+
attr_accessor :option
|
9
|
+
|
10
|
+
def self.option_help
|
11
|
+
{}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,54 +1,54 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'htot_conv/parser/base'
|
3
|
-
|
4
|
-
module HTOTConv
|
5
|
-
module Parser
|
6
|
-
class DirTree < Base
|
7
|
-
def self.option_help
|
8
|
-
{
|
9
|
-
:key_header => {
|
10
|
-
:default => [],
|
11
|
-
:pat => Array,
|
12
|
-
:desc => "key header",
|
13
|
-
},
|
14
|
-
:glob_pattern => {
|
15
|
-
:default => "**/*",
|
16
|
-
:pat => String,
|
17
|
-
:desc => "globbing pattern (default: \"**/*\")",
|
18
|
-
},
|
19
|
-
:dir_indicator => {
|
20
|
-
:default => "",
|
21
|
-
:pat => String,
|
22
|
-
:desc => "append directory indicator",
|
23
|
-
},
|
24
|
-
}
|
25
|
-
end
|
26
|
-
|
27
|
-
def parse(input=Dir.pwd)
|
28
|
-
outline = HTOTConv::Outline.new
|
29
|
-
outline.key_header = @option[:key_header]
|
30
|
-
outline.value_header = []
|
31
|
-
|
32
|
-
outline_item = Set.new
|
33
|
-
Dir.chdir(input) do
|
34
|
-
Dir.glob(@option[:glob_pattern]).each do |f|
|
35
|
-
f.split(File::SEPARATOR).inject(nil) do |parent_path, v|
|
36
|
-
file_path = (parent_path)? File.join(parent_path, v) : v
|
37
|
-
outline_item << file_path
|
38
|
-
file_path
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
outline_item.sort.each do |file_path|
|
43
|
-
key = File.basename(file_path)
|
44
|
-
key << "#{option[:dir_indicator]}" if FileTest.directory?(file_path)
|
45
|
-
level = file_path.split(File::SEPARATOR).length
|
46
|
-
outline.add_item(key, level, [])
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
outline
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'htot_conv/parser/base'
|
3
|
+
|
4
|
+
module HTOTConv
|
5
|
+
module Parser
|
6
|
+
class DirTree < Base
|
7
|
+
def self.option_help
|
8
|
+
{
|
9
|
+
:key_header => {
|
10
|
+
:default => [],
|
11
|
+
:pat => Array,
|
12
|
+
:desc => "key header",
|
13
|
+
},
|
14
|
+
:glob_pattern => {
|
15
|
+
:default => "**/*",
|
16
|
+
:pat => String,
|
17
|
+
:desc => "globbing pattern (default: \"**/*\")",
|
18
|
+
},
|
19
|
+
:dir_indicator => {
|
20
|
+
:default => "",
|
21
|
+
:pat => String,
|
22
|
+
:desc => "append directory indicator",
|
23
|
+
},
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse(input=Dir.pwd)
|
28
|
+
outline = HTOTConv::Outline.new
|
29
|
+
outline.key_header = @option[:key_header]
|
30
|
+
outline.value_header = []
|
31
|
+
|
32
|
+
outline_item = Set.new
|
33
|
+
Dir.chdir(input) do
|
34
|
+
Dir.glob(@option[:glob_pattern]).each do |f|
|
35
|
+
f.split(File::SEPARATOR).inject(nil) do |parent_path, v|
|
36
|
+
file_path = (parent_path)? File.join(parent_path, v) : v
|
37
|
+
outline_item << file_path
|
38
|
+
file_path
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
outline_item.sort.each do |file_path|
|
43
|
+
key = File.basename(file_path)
|
44
|
+
key << "#{option[:dir_indicator]}" if FileTest.directory?(file_path)
|
45
|
+
level = file_path.split(File::SEPARATOR).length
|
46
|
+
outline.add_item(key, level, [])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
outline
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|