htot_conv 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: db822ef12503c3c67ad25292d6843071c98ace01
4
+ data.tar.gz: 8bf51fe9de74f2ab6d135dd7a65f212df9d3a4dc
5
+ SHA512:
6
+ metadata.gz: 5d7e7917107721f317b69f02d18eacf268241e4fdee0bc601b927781fccd1e8cdf0faddb4dd99581bf75ed5e1e56ec744c58d2f7cad5ca601bb93d1cfa4db6e1
7
+ data.tar.gz: f3065da8d0f122319037639cc1934296a804d8080241bd5b611aa6f0372a2fbe7ff91e9c234e4f31a825c7f9c51a8ad8ce2684e20e6a31e2a27ae6386288b00e
data/.gitignore ADDED
@@ -0,0 +1,135 @@
1
+
2
+ # Created by https://www.gitignore.io/api/vim,emacs,ruby
3
+
4
+ ### Emacs ###
5
+ # -*- mode: gitignore; -*-
6
+ *~
7
+ \#*\#
8
+ /.emacs.desktop
9
+ /.emacs.desktop.lock
10
+ *.elc
11
+ auto-save-list
12
+ tramp
13
+ .\#*
14
+
15
+ # Org-mode
16
+ .org-id-locations
17
+ *_archive
18
+
19
+ # flymake-mode
20
+ *_flymake.*
21
+
22
+ # eshell files
23
+ /eshell/history
24
+ /eshell/lastdir
25
+
26
+ # elpa packages
27
+ /elpa/
28
+
29
+ # reftex files
30
+ *.rel
31
+
32
+ # AUCTeX auto folder
33
+ /auto/
34
+
35
+ # cask packages
36
+ .cask/
37
+ dist/
38
+
39
+ # Flycheck
40
+ flycheck_*.el
41
+
42
+ # server auth directory
43
+ /server/
44
+
45
+ # projectiles files
46
+ .projectile
47
+ projectile-bookmarks.eld
48
+
49
+ # directory configuration
50
+ .dir-locals.el
51
+
52
+ # saveplace
53
+ places
54
+
55
+ # url cache
56
+ url/cache/
57
+
58
+ # cedet
59
+ ede-projects.el
60
+
61
+ # smex
62
+ smex-items
63
+
64
+ # company-statistics
65
+ company-statistics-cache.el
66
+
67
+ # anaconda-mode
68
+ anaconda-mode/
69
+
70
+ ### Ruby ###
71
+ *.gem
72
+ *.rbc
73
+ /.config
74
+ /coverage/
75
+ /InstalledFiles
76
+ /pkg/
77
+ /spec/reports/
78
+ /spec/examples.txt
79
+ /test/tmp/
80
+ /test/version_tmp/
81
+ /tmp/
82
+
83
+ # Used by dotenv library to load environment variables.
84
+ # .env
85
+
86
+ ## Specific to RubyMotion:
87
+ .dat*
88
+ .repl_history
89
+ build/
90
+ *.bridgesupport
91
+ build-iPhoneOS/
92
+ build-iPhoneSimulator/
93
+
94
+ ## Specific to RubyMotion (use of CocoaPods):
95
+ #
96
+ # We recommend against adding the Pods directory to your .gitignore. However
97
+ # you should judge for yourself, the pros and cons are mentioned at:
98
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
99
+ #
100
+ # vendor/Pods/
101
+
102
+ ## Documentation cache and generated files:
103
+ /.yardoc/
104
+ /_yardoc/
105
+ /doc/
106
+ /rdoc/
107
+
108
+ ## Environment normalization:
109
+ /.bundle/
110
+ /vendor/bundle
111
+ /lib/bundler/man/
112
+
113
+ # for a library or gem, you might want to ignore these files since the code is
114
+ # intended to run in multiple environments; otherwise, check them in:
115
+ Gemfile.lock
116
+ # .ruby-version
117
+ # .ruby-gemset
118
+
119
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
120
+ .rvmrc
121
+
122
+ ### Vim ###
123
+ # swap
124
+ [._]*.s[a-v][a-z]
125
+ [._]*.sw[a-p]
126
+ [._]s[a-v][a-z]
127
+ [._]sw[a-p]
128
+ # session
129
+ Session.vim
130
+ # temporary
131
+ .netrwhist
132
+ # auto-generated tag files
133
+ tags
134
+
135
+ # End of https://www.gitignore.io/api/vim,emacs,ruby
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.3.4
6
+ before_install: gem install bundler -v 1.12.5
7
+ notifications:
8
+ email: false
9
+ slack:
10
+ secure: "XBa7qrPhwAl3D8C2mnzHHPlFcWj/IDjQ2+ab1P+oaWSzUd6kzFaQeuuBp21omIozfZwZNOLKRLTquN7vrenBL5h9+wtJsIzx5VK9bwPQijm8MAPQ4tWuhYTJfRmEQxhxkT/TKj+OhHLEgf1ZybDdw4PIsSjQEbpGr2Ro6pT13SS6DcmWPBM7eRryd0CN9Y2/bml94nF48LsNh4u5duTDHuB1+CD0dsbN+jtaPb0+rl2VK8+NrEhi4ghr4HKLvNRVyRLfc53aLsJyv5Wehhv5/iAJIeTXV/ys1TLEpt75FIDTTmZDj3zslHCShOuer8O1wXpofOXNOdbHjQ7tGjcg8nit6FezbjBJxPW6ocI3cq7Tl3lVcQqS0Z1s4mtfqgVm6Fw+eRtbFcXVSOu+NyS1ArlEYp624DKsFAb2asELKBD64r18dRSTecdD6LpUe5Dremw5OP4UfVcekbtNs31X/G11WZE6LGidfJjr3Yk9Y16T05ZykGtZDttykhFbDt8dd/YGu5f3rsPsPLVcTYa3ciVk4+e+V8rwNjUZ81o30ChS1PEedUsq7ttZ2QJj4wC6awdaLp+ue+yn7cjJPPZY3cpcgiVTaWjDjqyeGPB/sf0cVhB1nAnkR0d+YIBa+01v7uerfKpZ/UvJSDXCYy1GOFpKuajGgtQ0qd8ceNgcsmE="
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in htot_conv.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # HTOTConv - Hierarchical-Tree Outline Text Converter
2
+
3
+ Convert from a simple hierarchical-tree outline text into ugly xlsx file
4
+
5
+ ## Installation
6
+
7
+ Install `htot_conv` via RubyGems. Simply run the following command to install:
8
+
9
+ $ gem install htot_conv
10
+
11
+ ## Usage
12
+
13
+ $ cat outline.txt
14
+ President
15
+ .VP Marketing
16
+ ..Manager
17
+ ..Manager
18
+ .VP Production
19
+ ..Manager
20
+ ..Manager
21
+ .VP Sales
22
+ ..Manager
23
+ ..Manager
24
+ $ htot_conv -f simple_text --from-indent=. -t xlsx_type2 outline.txt outline.xlsx
25
+ $ xdg-open outline.xlsx
26
+
27
+ ### Types of input
28
+
29
+ #### `simple_text`
30
+
31
+ * A text file consisting of multiple lines where:
32
+ * `<line> ::= { <indent> } <key> { <delimiter> <value> }`
33
+ * `<key>` : a text that does not start with `<indent>` and does not contain `<delimiter>` (if `<delimiter>` specified).
34
+ * `<value>` : a text that does not contain `<delimiter>`.
35
+ * `<indent>` : specified by `--from-indent` option
36
+ * `<delimiter>` : specified by `--from-delimiter` option
37
+
38
+ #### `html_list`
39
+
40
+ * HTML `<ul><li>` and/or `<ol><li>` [nesting list](https://www.w3.org/wiki/HTML_lists#Nesting_lists).
41
+ * All text outside of `<li>` elements is ignored.
42
+
43
+ ### Types of output
44
+
45
+ The sample input used in this section are as follows:
46
+
47
+ 1,1(1),1(2)
48
+ 1.1,1.1(1),1.1(2)
49
+ 1.2,1.2(1),1.2(2)
50
+ 1.2.1,1.2.1(1),1.2.1(2)
51
+
52
+ * key header: H1, H2, H3
53
+ * value header: H(1), H(2)
54
+
55
+ #### `xlsx_type0`
56
+
57
+ | H1 | Level | H(1) | H(2) |
58
+ |-------|-------|----------|----------|
59
+ | 1 | 1 | 1(1) | 1(2) |
60
+ | 1.1 | 2 | 1.1(1) | 1.1(2) |
61
+ | 1.2 | 2 | 1.2(1) | 1.2(2) |
62
+ | 1.2.1 | 3 | 1.2.1(1) | 1.2.1(2) |
63
+
64
+ #### `xlsx_type1`
65
+
66
+ | H1 | H(1) | H(2) |
67
+ |-------|----------|----------|
68
+ | 1 | 1(1) | 1(2) |
69
+ | 1.1 | 1.1(1) | 1.1(2) |
70
+ | 1.2 | 1.2(1) | 1.2(2) |
71
+ | 1.2.1 | 1.2.1(1) | 1.2.1(2) |
72
+
73
+ Not implemented (TODO):
74
+
75
+ * Fill with different background color for each level.
76
+
77
+ #### `xlsx_type2`
78
+
79
+ | H1 | H2 | H3 | H(1) | H(2) |
80
+ |----|-----|-------|----------|----------|
81
+ | 1 | | | 1(1) | 1(2) |
82
+ | | 1.1 | | 1.1(1) | 1.1(2) |
83
+ | | 1.2 | | 1.2(1) | 1.2(2) |
84
+ | | | 1.2.1 | 1.2.1(1) | 1.2.1(2) |
85
+
86
+ Not implemented (TODO):
87
+
88
+ * Cell integration over row.
89
+
90
+ #### `xlsx_type3`
91
+
92
+ Not supported (implemented) as of now.
93
+
94
+ | H1 | H(1) | | | H(2) |
95
+ |----|------|--------|----------|----------|
96
+ | 1 | 1(1) | | | 1(2) |
97
+ | | 1.1 | 1.1(1) | | 1.1(2) |
98
+ | | 1.2 | 1.2(1) | | 1.2(2) |
99
+ | | | 1.2.1 | 1.2.1(1) | 1.2.1(2) |
100
+
101
+ TODO: Github Flavored Markdown does not support for column span.
102
+ So, this document does not correctly represent type-3 xlsx spread sheet.
103
+
104
+ #### `xlsx_type4`
105
+
106
+ | H1 | H2 | H3 | H(1) | H(2) |
107
+ |----|-----|-------|----------|----------|
108
+ | 1 | 1.1 | | 1.1(1) | 1.1(2) |
109
+ | | 1.2 | 1.2.1 | 1.2.1(1) | 1.2.1(2) |
110
+
111
+ Not implemented (TODO):
112
+
113
+ * Cell integration over column.
114
+
115
+ #### `xlsx_type5`
116
+
117
+ | H1 | H2 | H3 | H(1) | H(2) |
118
+ |----|-----|-------|----------|----------|
119
+ | 1 | 1.1 | | 1.1(1) | 1.1(2) |
120
+ | 1 | 1.2 | 1.2.1 | 1.2.1(1) | 1.2.1(2) |
121
+
122
+ Not implemented (TODO):
123
+
124
+ * Cell integration over column.
125
+ * Apply auto filter to the first (header) row.
126
+
127
+ ## Development
128
+
129
+ $ bundle install --path=vendor/bundle --with development test
130
+ $ bundle exec rake test
131
+
132
+ ## Contributing
133
+
134
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/cat-in-136/htot_conv>.
135
+
136
+
137
+ ## License
138
+
139
+ [MIT License](http://opensource.org/licenses/MIT).
140
+ See the `LICENSE.txt` file.
141
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "htot_conv"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/htot_conv ADDED
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ require 'rubygems'
5
+ require 'rinne'
6
+ require 'htot_conv'
7
+
8
+ module HTOTConv
9
+ module CLI
10
+ class ScriptOptions
11
+ def initialize
12
+ @options = {
13
+ :from_type => :simple_text,
14
+ :to_type => :xlsx_type2,
15
+ }
16
+ @from_options = {}
17
+ @to_options = {}
18
+ end
19
+ attr_accessor :options, :from_options, :to_options
20
+
21
+ def define_options(opts)
22
+ opts.banner = %q{Hierarchical-Tree Outline Text Converter}
23
+ opts.define_head %q{Usage: htot_conv [options] [input] [output]}
24
+ opts.separator %q{}
25
+ opts.separator %q{Options:}
26
+
27
+ from_types = HTOTConv::Parser.types.map { |v| [v, v.to_s.tr("_", "-")] }.flatten
28
+ to_types = HTOTConv::Generator.types.map { |v| [v, v.to_s.tr("_", "-")] }.flatten
29
+
30
+ opts.on("-f", "--from-type=TYPE", from_types, "type of input (default: #{options[:from_type]})") do |v|
31
+ options[:from_type] = v.to_s.tr("-", "_")
32
+ end
33
+ opts.on("-t", "--to-type=TYPE", to_types, "type of output (default: #{options[:to_type]})") do |v|
34
+ options[:to_type] = v.to_s.tr("-", "_")
35
+ end
36
+ opts.on("-l", "--list-type", "list input/output type") do
37
+ $stdout << "type of input:\n"
38
+ $stdout << HTOTConv::Parser.types.join(" ") << "\n"
39
+ $stdout << "\n"
40
+ $stdout << "type of output:\n"
41
+ $stdout << HTOTConv::Generator.types.join(" ") << "\n"
42
+ $stdout << "\n"
43
+ exit
44
+ end
45
+
46
+ opts.separator ""
47
+ opts.on("-h", "-?", "--help", "Show this message") do
48
+ puts opts
49
+ exit
50
+ end
51
+ opts.on("--version", "Show version") do
52
+ $stdout << "htot_conv #{HTOTConv::VERSION}\n"
53
+ exit
54
+ end
55
+
56
+ opts.separator ""
57
+ opts.separator "I/O Options:"
58
+ define_sub_options(opts, HTOTConv::Parser, "from") do |key, v|
59
+ @from_options[key] = v
60
+ end
61
+ define_sub_options(opts, HTOTConv::Generator, "to") do |key, v|
62
+ @to_options[key] = v
63
+ end
64
+ end
65
+
66
+ private
67
+ def define_sub_options(opts, klass, prefix) # :yields: key, v
68
+ klass.types.each do |type|
69
+ type_klass = klass.const_get(Rinne.camelize(type.to_s))
70
+ type_klass.option_help.each do |key,v|
71
+ long_option = "--#{prefix}-#{key.to_s.tr('_','-')}=VAL"
72
+ cmd_switch = opts.top.list.find { |v| v.kind_of?(OptionParser::Switch) && v.long.include?(long_option) }
73
+ if cmd_switch
74
+ cmd_switch.desc << "For #{type}, #{v[:desc]}"
75
+ else
76
+ opts.on(long_option, v[:pat], "For #{type}, #{v[:desc]}") do |v|
77
+ yield key, v
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def optparse(args)
86
+ script_opts = ScriptOptions.new
87
+ OptionParser.new do |opts|
88
+ script_opts.define_options(opts)
89
+
90
+ begin
91
+ opts.parse!(args)
92
+ rescue OptionParser::ParseError => ex
93
+ $stderr << ex.message << "\n"
94
+ exit 1
95
+ end
96
+ end
97
+ script_opts
98
+ end
99
+ module_function :optparse
100
+ end
101
+ end
102
+
103
+ script_opts = HTOTConv::CLI.optparse(ARGV)
104
+ options = script_opts.options
105
+ from_options = script_opts.from_options
106
+ to_options = script_opts.to_options
107
+
108
+ inio = ((ARGV.length > 0) && (ARGV[0] != "-"))? File.open(ARGV[0], "rb") : $stdin
109
+ outio = ((ARGV.length > 1) && (ARGV[1] != "-"))? File.open(ARGV[1], "wb") : $stdout
110
+
111
+ HTOTConv.convert(inio, options[:from_type], outio, options[:to_type], from_options, to_options)
data/htot_conv.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'htot_conv/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "htot_conv"
8
+ spec.version = HTOTConv::VERSION
9
+ spec.authors = ["@cat_in_136"]
10
+ spec.email = ["cat.in.136+github@gmail.com"]
11
+
12
+ spec.summary = %q{Hierarchical-Tree Outline Text Converter}
13
+ spec.description = %q{Convert from a simple hierarchical-tree outline text into ugly xlsx file}
14
+ spec.homepage = "https://github.com/cat-in-136/htot_conv"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ #spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "axlsx", "~> 2.0.1"
31
+ spec.add_dependency "rinne", "~> 0.0.3"
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.12"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "minitest", "~> 5.0"
36
+ end
@@ -0,0 +1,34 @@
1
+ module HTOTConv
2
+ module Generator
3
+ class Base
4
+ def initialize(data, option={})
5
+ @data = data
6
+ @option = self.class.option_help.inject({}) { |h, pair| h[pair[0]] = pair[1][:default]; h}.merge(option)
7
+ raise ArgumentError, "data is invalid" unless data.valid?
8
+ end
9
+ def self.option_help
10
+ {}
11
+ end
12
+
13
+ def output(outputfile)
14
+ raise NotImplementedError.new("#{self.class.name}.#{__method__} is an abstract method.")
15
+ end
16
+ end
17
+
18
+ class XlsxBase < Base
19
+ def output_to_worksheet(ws)
20
+ raise NotImplementedError.new("#{self.class.name}.#{__method__} is an abstract method.")
21
+ end
22
+
23
+ def output(outputfile)
24
+ p = Axlsx::Package.new
25
+ p.workbook do |wb|
26
+ wb.add_worksheet do |ws|
27
+ output_to_worksheet(ws)
28
+ end
29
+ end
30
+ p.serialize(outputfile)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ require 'axlsx'
2
+
3
+ require 'htot_conv/generator/base'
4
+
5
+ module HTOTConv
6
+ module Generator
7
+ class XlsxType0 < XlsxBase
8
+ def output_to_worksheet(ws)
9
+ max_value_length = @data.max_value_length
10
+
11
+ ws.add_row([@data.key_header[0], 'Level'].concat(
12
+ HTOTConv::Util.pad_array(@data.value_header, max_value_length)),
13
+ :style => Axlsx::STYLE_THIN_BORDER)
14
+
15
+ @data.item.each do |item|
16
+ ws.add_row([item.key, item.level.to_i].concat(
17
+ HTOTConv::Util.pad_array(item.value, max_value_length)),
18
+ :style => Axlsx::STYLE_THIN_BORDER)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+
2
+ require 'axlsx'
3
+
4
+ require 'htot_conv/generator/base'
5
+
6
+ module HTOTConv
7
+ module Generator
8
+ class XlsxType1 < XlsxBase
9
+ def output_to_worksheet(ws)
10
+ max_value_length = @data.max_value_length
11
+
12
+ ws.add_row([@data.key_header[0]].concat(
13
+ HTOTConv::Util.pad_array(@data.value_header, max_value_length)),
14
+ :style => Axlsx::STYLE_THIN_BORDER)
15
+
16
+ @data.item.each do |item|
17
+ ws.add_row([item.key].concat(
18
+ HTOTConv::Util.pad_array(item.value, max_value_length)),
19
+ :style => Axlsx::STYLE_THIN_BORDER)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,37 @@
1
+ require 'axlsx'
2
+
3
+ require 'htot_conv/generator/base'
4
+
5
+ module HTOTConv
6
+ module Generator
7
+ class XlsxType2 < XlsxBase
8
+ def output_to_worksheet(ws)
9
+ max_level = @data.max_level
10
+ max_value_length = @data.max_value_length
11
+
12
+ ws.add_row(((1..max_level).map {|l| @data.key_header[l - 1] || nil }).concat(
13
+ HTOTConv::Util.pad_array(@data.value_header, max_value_length)),
14
+ :style => Axlsx::STYLE_THIN_BORDER)
15
+
16
+ @data.item.each_with_index do |item, item_index|
17
+ key_cell = Array.new(max_level, nil)
18
+ key_cell[item.level - 1] = item.key
19
+ value_cell = HTOTConv::Util.pad_array(item.value, max_value_length)
20
+
21
+ ws.add_row(key_cell.concat(value_cell),
22
+ :style => Axlsx::STYLE_THIN_BORDER)
23
+
24
+ (1..max_level).each do |level|
25
+ edges = []
26
+ edges << :left if (level <= item.level)
27
+ edges << :right if ((level < item.level) || (level == max_level))
28
+ edges << :top if ((level >= item.level) || (item_index == 0))
29
+ edges << :bottom if ((level > item.level) || (item_index == @data.item.length - 1))
30
+ ws.rows.last.cells[level - 1].style = ws.styles.add_style(
31
+ :border => { :style => :thin, :color => "00", :edges => edges })
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,53 @@
1
+ require 'axlsx'
2
+
3
+ require 'htot_conv/generator/base'
4
+
5
+ module HTOTConv
6
+ module Generator
7
+ class XlsxType4 < XlsxBase
8
+ def output_to_worksheet(ws)
9
+ max_level = @data.max_level
10
+ max_value_length = @data.max_value_length
11
+
12
+ ws.add_row(((1..max_level).map {|l| @data.key_header[l - 1] || nil }).concat(
13
+ HTOTConv::Util.pad_array(@data.value_header, max_value_length)),
14
+ :style => Axlsx::STYLE_THIN_BORDER)
15
+
16
+ @data.to_tree.descendants.each do |node|
17
+ if node.leaf?
18
+ item = node.item
19
+
20
+ key_cell = Array.new(max_level, nil)
21
+ key_cell[node.item.level - 1] = item.key
22
+ node.ancestors do |ancestor|
23
+ key_cell[ancestor.item.level - 1] = ancestor.item.key if ancestor.item
24
+ break if ancestor.prev
25
+ end
26
+
27
+ value_cell = HTOTConv::Util.pad_array(item.value, max_value_length)
28
+
29
+ ws.add_row(key_cell.concat(value_cell),
30
+ :style => Axlsx::STYLE_THIN_BORDER)
31
+
32
+ [node].concat(node.ancestors).each do |ancestor|
33
+ if (ancestor.parent && ancestor.parent.item && ancestor.parent.item.level)
34
+ edges = [:left, :right]
35
+ edges << :top unless ancestor.prev
36
+ edges << :bottom unless ancestor.next
37
+ ws.rows.last.cells[ancestor.parent.item.level - 1].style = ws.styles.add_style(
38
+ :border => { :style => :thin, :color => "00", :edges => edges })
39
+ end
40
+ end
41
+ (item.level..max_level).each do |level|
42
+ edges = [:top, :bottom]
43
+ edges << :left if (level == item.level)
44
+ edges << :right if (level == max_level)
45
+ ws.rows.last.cells[level - 1].style = ws.styles.add_style(
46
+ :border => { :style => :thin, :color => "00", :edges => edges })
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,45 @@
1
+ require 'axlsx'
2
+
3
+ require 'htot_conv/generator/base'
4
+
5
+ module HTOTConv
6
+ module Generator
7
+ class XlsxType5 < XlsxBase
8
+ def output_to_worksheet(ws)
9
+ max_level = @data.max_level
10
+ max_value_length = @data.max_value_length
11
+
12
+ ws.add_row(((1..max_level).map {|l| @data.key_header[l - 1] || nil }).concat(
13
+ HTOTConv::Util.pad_array(@data.value_header, max_value_length)),
14
+ :style => Axlsx::STYLE_THIN_BORDER)
15
+
16
+ @data.to_tree.descendants.each do |node|
17
+ if node.leaf?
18
+ item = node.item
19
+
20
+ key_cell = Array.new(max_level, nil)
21
+ key_cell[node.item.level - 1] = item.key
22
+ node.ancestors do |ancestor|
23
+ key_cell[ancestor.item.level - 1] = ancestor.item.key if ancestor.item
24
+ end
25
+
26
+ value_cell = HTOTConv::Util.pad_array(item.value, max_value_length)
27
+
28
+ ws.add_row(key_cell.concat(value_cell),
29
+ :style => Axlsx::STYLE_THIN_BORDER)
30
+
31
+ (item.level..max_level).each do |level|
32
+ edges = [:top, :bottom]
33
+ edges << :left if (level == item.level)
34
+ edges << :right if (level == max_level)
35
+ ws.rows.last.cells[level - 1].style = ws.styles.add_style(
36
+ :border => { :style => :thin, :color => "00", :edges => edges })
37
+ end
38
+ end
39
+ end
40
+
41
+ ws.auto_filter = "A1:#{ws.rows.last.cells[max_level + max_value_length - 1].r}"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ require 'htot_conv/generator/xlsx_type0.rb'
2
+ require 'htot_conv/generator/xlsx_type1.rb'
3
+ require 'htot_conv/generator/xlsx_type2.rb'
4
+ require 'htot_conv/generator/xlsx_type4.rb'
5
+ require 'htot_conv/generator/xlsx_type5.rb'
6
+
7
+ require 'rinne'
8
+
9
+ module HTOTConv
10
+ module Generator
11
+ def create(type, *args)
12
+ klass = HTOTConv::Generator.const_get(Rinne.camelize(type.to_s))
13
+ klass.new(*args)
14
+ end
15
+ module_function :create
16
+
17
+ def types
18
+ HTOTConv::Generator.constants.reject { |klass|
19
+ klass =~ /Base$/
20
+ }.select { |klass|
21
+ HTOTConv::Generator.const_get(klass).kind_of?(Class)
22
+ }.map { |klass|
23
+ Rinne.to_snake(klass.to_s).to_sym
24
+ }
25
+ end
26
+ module_function :types
27
+ end
28
+ end
@@ -0,0 +1,157 @@
1
+ module HTOTConv
2
+ class Outline
3
+ def initialize
4
+ @item = []
5
+ end
6
+
7
+ attr_accessor :key_header
8
+ attr_accessor :value_header
9
+ attr_accessor :item
10
+
11
+ def add_item(*args)
12
+ @item << Item.new(*args)
13
+ end
14
+
15
+ def valid?
16
+ @key_header.kind_of?(Array) &&
17
+ @key_header.all? { |v| v.nil? || v.kind_of?(String) } &&
18
+ @value_header.kind_of?(Array) &&
19
+ @value_header.all? { |v| v.nil? || v.kind_of?(String) } &&
20
+ @item.kind_of?(Array) &&
21
+ @item.all? { |item| item.valid? }
22
+ end
23
+
24
+ def max_level
25
+ [
26
+ @key_header.length,
27
+ *(@item.map { |v| v.level.to_i }),
28
+ ].max
29
+ end
30
+
31
+ def max_value_length
32
+ [
33
+ @value_header.length,
34
+ *(@item.map { |v| (v.value)? v.value.length : 0 }),
35
+ ].max
36
+ end
37
+
38
+ def ==(v)
39
+ (@key_header == v.key_header) &&
40
+ (@value_header == v.value_header) &&
41
+ (@item == v.item)
42
+ end
43
+
44
+ def to_tree
45
+ root = Tree.new
46
+ last_node = root
47
+ @item.each_with_index do |item,i|
48
+ parent_node = root
49
+ if ((item.level > 1) && !(last_node.root?))
50
+ if item.level > last_node.item.level
51
+ parent_node = last_node
52
+ else
53
+ parent_node = last_node.parent
54
+ parent_node = parent_node.parent until (parent_node.root? || parent_node.item.level < item.level)
55
+ end
56
+ end
57
+
58
+ parent_node << item
59
+ last_node = parent_node.to_a.last
60
+ end
61
+ root
62
+ end
63
+
64
+ Item = Struct.new(:key, :level, :value) do
65
+ def valid?
66
+ self.level.kind_of?(Numeric) &&
67
+ (self.level > 0) &&
68
+ (self.level.to_i == self.level) &&
69
+ self.value.kind_of?(Array)
70
+ end
71
+ end
72
+
73
+ class Tree
74
+ include Enumerable
75
+
76
+ def initialize(item=nil, parent=nil)
77
+ @item = item
78
+ @parent = parent
79
+ @children = []
80
+ end
81
+ attr_accessor :item
82
+ attr_reader :parent
83
+
84
+ def root?
85
+ @parent.nil?
86
+ end
87
+
88
+ def leaf?
89
+ @children.empty?
90
+ end
91
+
92
+ def add(item)
93
+ child = Tree.new(item, self)
94
+ @children << child
95
+ self
96
+ end
97
+ alias :<< :add
98
+
99
+ def each # :yields: child
100
+ @children.each do |v|
101
+ yield v if block_given?
102
+ end
103
+ @children.dup
104
+ end
105
+
106
+ def root
107
+ node = self
108
+ node = node.parent until node.root?
109
+ node
110
+ end
111
+
112
+ def next
113
+ if root?
114
+ nil
115
+ else
116
+ brothers = parent.to_a
117
+ index = brothers.index(self)
118
+ (index + 1 < brothers.length)? brothers[index + 1] : nil
119
+ end
120
+ end
121
+
122
+ def prev
123
+ if root?
124
+ nil
125
+ else
126
+ brothers = parent.to_a
127
+ index = brothers.index(self)
128
+ (index - 1 >= 0)? brothers[index - 1] : nil
129
+ end
130
+ end
131
+
132
+ def ancestors # :yields: ancestor
133
+ ancestors = []
134
+ node = self.parent
135
+ until (node.nil? || node.root?)
136
+ ancestors << node
137
+ yield node if block_given?
138
+ node = node.parent
139
+ end
140
+ ancestors
141
+ end
142
+
143
+ def descendants # :yields: descendant
144
+ descendants = []
145
+ @children.each do |child|
146
+ descendants << child
147
+ yield child if block_given?
148
+ child.descendants do |descendant|
149
+ descendants << descendant
150
+ yield descendant if block_given?
151
+ end
152
+ end
153
+ descendants
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,14 @@
1
+ module HTOTConv
2
+ module Parser
3
+ class Base
4
+ def initialize(option={})
5
+ @option = self.class.option_help.inject({}) { |h, pair| h[pair[0]] = pair[1][:default]; h}.merge(option)
6
+ end
7
+ attr_accessor :option
8
+
9
+ def self.option_help
10
+ {}
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,60 @@
1
+ require 'htot_conv/parser/base'
2
+
3
+ module HTOTConv
4
+ module Parser
5
+ class HtmlList < Base
6
+ def parse(input)
7
+ outline = HTOTConv::Outline.new
8
+ outline.key_header = []
9
+ outline.value_header = []
10
+
11
+ parser = Nokogiri::HTML::SAX::Parser.new(ListDoc.new(outline))
12
+ parser.parse(input)
13
+
14
+ outline
15
+ end
16
+
17
+ class ListDoc < Nokogiri::XML::SAX::Document
18
+ def initialize(outline)
19
+ @outline = outline
20
+ @breadcrumb = []
21
+ @li_text = nil
22
+ end
23
+
24
+ def start_element(name, attrs=[])
25
+ if ((name == "ul") || (name == "ol"))
26
+ generate_outline_item unless @li_text.nil?
27
+ @breadcrumb << name
28
+ elsif name == "li"
29
+ @li_text = "".dup if @breadcrumb.length > 0
30
+ end
31
+ end
32
+
33
+ def end_element(name)
34
+ if ((name == "ul") || (name == "ol"))
35
+ generate_outline_item unless @li_text.nil?
36
+ @breadcrumb.pop
37
+ elsif name == "li"
38
+ generate_outline_item unless @li_text.nil?
39
+ end
40
+ end
41
+
42
+ def characters(string)
43
+ @li_text << string unless @li_text.nil?
44
+ end
45
+
46
+ def cdata_block(string)
47
+ @li_text << string unless @li_text.nil?
48
+ end
49
+
50
+ private
51
+ def generate_outline_item
52
+ level = @breadcrumb.length
53
+ @outline.add_item(@li_text.strip, level, [])
54
+ @li_text = nil
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,52 @@
1
+ require 'htot_conv/parser/base'
2
+
3
+ module HTOTConv
4
+ module Parser
5
+ class SimpleText < Base
6
+ def self.option_help
7
+ {
8
+ :indent => {
9
+ :default => "\t",
10
+ :pat => String,
11
+ :desc => "indent character (default: TAB)",
12
+ },
13
+ :delimiter => {
14
+ :default => nil,
15
+ :pat => String,
16
+ :desc => "separator character of additional data"
17
+ },
18
+ }
19
+ end
20
+
21
+ def parse(input)
22
+ indent_regexp = Regexp.new("^(?<indents>(#{Regexp.escape(option[:indent])})*)")
23
+ delimiter_regexp = (option[:delimiter].kind_of?(String))? Regexp.new(Regexp.escape(option[:delimiter])) : option[:delimiter]
24
+ outline = HTOTConv::Outline.new
25
+ outline.key_header = []
26
+ outline.value_header = []
27
+
28
+ input.each_line do |line|
29
+ level = 1
30
+ value = []
31
+ if (option[:indent] || '').length > 0
32
+ indents = indent_regexp.match(line)[:indents]
33
+ level = 1 + indents.length / option[:indent].length
34
+ line = line.sub(indent_regexp, "")
35
+ end
36
+
37
+ line = line.strip
38
+ if delimiter_regexp
39
+ key = line.split(delimiter_regexp)[0]
40
+ value = line.split(delimiter_regexp)[1..-1] || []
41
+ else
42
+ key = line
43
+ end
44
+
45
+ outline.add_item(key, level, value)
46
+ end
47
+
48
+ outline
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,24 @@
1
+ require 'htot_conv/parser/base.rb'
2
+ require 'htot_conv/parser/simple_text.rb'
3
+ require 'htot_conv/parser/html_list.rb'
4
+
5
+ module HTOTConv
6
+ module Parser
7
+ def create(type, *args)
8
+ klass = HTOTConv::Parser.const_get(Rinne.camelize(type.to_s))
9
+ klass.new(*args)
10
+ end
11
+ module_function :create
12
+
13
+ def types
14
+ HTOTConv::Parser.constants.reject { |klass|
15
+ klass =~ /Base$/
16
+ }.select { |klass|
17
+ HTOTConv::Parser.const_get(klass).kind_of?(Class)
18
+ }.map { |klass|
19
+ Rinne.to_snake(klass.to_s).to_sym
20
+ }
21
+ end
22
+ module_function :types
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module HTOTConv
3
+ module Util
4
+ def pad_array(array, length, pad=nil)
5
+ raise ArgumentError, "array is not an array" unless array.kind_of?(Array)
6
+ raise ArgumentError, "array length #{array.length} is larger than #{length}" if array.length > length
7
+
8
+ array.concat(Array.new(length - array.length, pad))
9
+ end
10
+ module_function :pad_array
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module HTOTConv
2
+ VERSION = "0.0.1"
3
+ end
data/lib/htot_conv.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'htot_conv/version'
2
+
3
+ require 'htot_conv/util'
4
+ require 'htot_conv/outline'
5
+ require 'htot_conv/generator'
6
+ require 'htot_conv/parser'
7
+
8
+ module HTOTConv
9
+
10
+ def convert(input, input_type, output, output_type, input_option={}, output_option={})
11
+ parser = HTOTConv::Parser.create(input_type, input_option)
12
+ outline = parser.parse(input)
13
+ generator = HTOTConv::Generator.create(output_type, outline, output_option)
14
+ generator.output(output)
15
+ end
16
+ module_function :convert
17
+
18
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: htot_conv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - "@cat_in_136"
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-09-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: axlsx
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rinne
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.0'
83
+ description: Convert from a simple hierarchical-tree outline text into ugly xlsx file
84
+ email:
85
+ - cat.in.136+github@gmail.com
86
+ executables:
87
+ - htot_conv
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - bin/console
98
+ - bin/setup
99
+ - exe/htot_conv
100
+ - htot_conv.gemspec
101
+ - lib/htot_conv.rb
102
+ - lib/htot_conv/generator.rb
103
+ - lib/htot_conv/generator/base.rb
104
+ - lib/htot_conv/generator/xlsx_type0.rb
105
+ - lib/htot_conv/generator/xlsx_type1.rb
106
+ - lib/htot_conv/generator/xlsx_type2.rb
107
+ - lib/htot_conv/generator/xlsx_type4.rb
108
+ - lib/htot_conv/generator/xlsx_type5.rb
109
+ - lib/htot_conv/outline.rb
110
+ - lib/htot_conv/parser.rb
111
+ - lib/htot_conv/parser/base.rb
112
+ - lib/htot_conv/parser/html_list.rb
113
+ - lib/htot_conv/parser/simple_text.rb
114
+ - lib/htot_conv/util.rb
115
+ - lib/htot_conv/version.rb
116
+ homepage: https://github.com/cat-in-136/htot_conv
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.5.2.1
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Hierarchical-Tree Outline Text Converter
140
+ test_files: []