htot_conv 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2aec83d272692c2e5e421fa83871202a6658f6f0
4
- data.tar.gz: 2e36a66a3309075cb170a1e587e18d83fc3a1c97
3
+ metadata.gz: 5d55ad5f2d58f0e79c06559e63d2a8916b34aa31
4
+ data.tar.gz: c08cb89b3d16f61f9a529fd78eb69d4eda2979ae
5
5
  SHA512:
6
- metadata.gz: aea65eb03fa27f1d475448e8bf560a387e36c564d8af92b6e68e99701569d10544496841458c840eff89e815ba2e3857140d0d7e1b43e932f6c5a3c616be53b9
7
- data.tar.gz: fefabfb0d96991003bb55d53590fc26bbbc1c2a1947d5ba92a7188852ad8491408ff7f5b4399d3f179bbd8fb8b4e586139cc55a8576e8cdb9d3d538b270ce31e
6
+ metadata.gz: 3437bfd4648e1b5422a84ac848fd7271bb1b2f71b6a98080864af56e1dc4800a749cce2f30e1327c456ad1f802a855e27f16083d9e0a56215b5ae26e13ca8b3c
7
+ data.tar.gz: 1147a7ad351c344f6b1e53cdb5e5330ae23a24ffe5e6b8b94f1e2eb718c4bf5c6481ba739920f17f2a78edefad6bd84de0bbf1a593bf0f56b2d291da2db2ed9f
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2017 TODO: Write your name
3
+ Copyright (c) 2017 cat_in_136
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -38,11 +38,20 @@ Install `htot_conv` via RubyGems. Simply run the following command to install:
38
38
  * `<indent>` : specified by `--from-indent` option
39
39
  * `<delimiter>` : specified by `--from-delimiter` option
40
40
 
41
+ #### `dir_tree`
42
+
43
+ * Directory tree with the glob pattern specified by `--from-glob-pattern` (default: `**/*`)
44
+
41
45
  #### `html_list`
42
46
 
43
47
  * HTML `<ul><li>` and/or `<ol><li>` [nesting list](https://www.w3.org/wiki/HTML_lists#Nesting_lists).
44
48
  * All text outside of `<li>` elements is ignored.
45
49
 
50
+ #### `opml`
51
+
52
+ * [OPML](http://dev.opml.org/)
53
+ * Treat the `text` attribute as a key text, the other attributes as values.
54
+
46
55
  ### Types of output
47
56
 
48
57
  The sample input used in this section are as follows:
@@ -88,8 +97,6 @@ Not implemented (TODO):
88
97
 
89
98
  #### `xlsx_type3`
90
99
 
91
- Not supported (implemented) as of now.
92
-
93
100
  | H1 | H(1) | | | H(2) |
94
101
  |----|------|--------|----------|----------|
95
102
  | 1 | 1(1) | | | 1(2) |
@@ -97,7 +104,7 @@ Not supported (implemented) as of now.
97
104
  | | 1.2 | 1.2(1) | | 1.2(2) |
98
105
  | | | 1.2.1 | 1.2.1(1) | 1.2.1(2) |
99
106
 
100
- TODO: Github Flavored Markdown does not support for row span.
107
+ TODO: Github Flavored Markdown does not support the column span.
101
108
  So, this document does not correctly represent type-3 xlsx spread sheet.
102
109
 
103
110
  #### `xlsx_type4`
data/htot_conv.gemspec CHANGED
@@ -33,4 +33,5 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency "bundler", "~> 1.12"
34
34
  spec.add_development_dependency "rake", "~> 10.0"
35
35
  spec.add_development_dependency "minitest", "~> 5.0"
36
+ spec.add_development_dependency "fakefs", "~> 0.11.3"
36
37
  end
@@ -3,9 +3,9 @@ module HTOTConv
3
3
  module Generator
4
4
  class Base
5
5
  def initialize(data, option={})
6
+ data.validate
6
7
  @data = data
7
8
  @option = self.class.option_help.inject({}) { |h, pair| h[pair[0]] = pair[1][:default]; h}.merge(option)
8
- raise ArgumentError, "data is invalid" unless data.valid?
9
9
  end
10
10
  def self.option_help
11
11
  {}
@@ -9,7 +9,7 @@ module HTOTConv
9
9
  def output_to_worksheet(ws)
10
10
  max_value_length = @data.max_value_length
11
11
 
12
- ws.add_row([@data.key_header[0], 'Level'].concat(
12
+ ws.add_row([@data.key_header[0], 'Outline Level'].concat(
13
13
  HTOTConv::Util.pad_array(@data.value_header, max_value_length)),
14
14
  :style => Axlsx::STYLE_THIN_BORDER)
15
15
 
@@ -7,6 +7,16 @@ require 'htot_conv/generator/base'
7
7
  module HTOTConv
8
8
  module Generator
9
9
  class XlsxType1 < XlsxBase
10
+ def self.option_help
11
+ {
12
+ :outline_rows => {
13
+ :default => false,
14
+ :pat => FalseClass,
15
+ :desc => "group rows (default: no)",
16
+ },
17
+ }
18
+ end
19
+
10
20
  def output_to_worksheet(ws)
11
21
  max_value_length = @data.max_value_length
12
22
 
@@ -19,6 +29,39 @@ module HTOTConv
19
29
  HTOTConv::Util.pad_array(item.value, max_value_length)),
20
30
  :style => Axlsx::STYLE_THIN_BORDER)
21
31
  end
32
+
33
+ if @option[:outline_rows]
34
+ max_level = @data.max_level
35
+ outline_begin = Array.new(max_level, nil)
36
+ dummy_end_item = HTOTConv::Outline::Item.new(nil, 1, nil)
37
+ @data.item.concat([dummy_end_item]).each_with_index do |item, item_index|
38
+ (item.level..max_level).each do |level|
39
+ if outline_begin[level - 1]
40
+ if outline_begin[level - 1] < item_index - 1
41
+ ws.outline_level_rows((outline_begin[level - 1] + 1) + 1, (item_index - 1) + 1, level, false)
42
+ end
43
+ outline_begin[level - 1] = nil
44
+ end
45
+ end
46
+ outline_begin[item.level - 1] = item_index
47
+ end
48
+
49
+ # PR randym/axlsx#440 has been added to master branch
50
+ # https://github.com/randym/axlsx/commit/c80c8b9d9be5542471d66afcc2ce4ddd80cac1f7
51
+ # but latest release on rubygems does not contain this.
52
+ # So apply monkey patch to ws.sheet_pr.
53
+ if defined? ws.sheet_pr.outline_pr
54
+ ws.sheet_pr.outline_pr.summary_below = false
55
+ else
56
+ class << ws.sheet_pr # monkey patch
57
+ def to_xml_string(str="".dup)
58
+ tmp_str = "".dup
59
+ super(tmp_str)
60
+ str << tmp_str.sub('<pageSetUpPr', '<outlinePr summaryBelow="0" /><pageSetUpPr')
61
+ end
62
+ end
63
+ end
64
+ end
22
65
  end
23
66
  end
24
67
  end
@@ -13,6 +13,11 @@ module HTOTConv
13
13
  :pat => [:colspan, :rowspan],
14
14
  :desc => "integrate key cells (specify 'colspan' or 'rowspan')",
15
15
  },
16
+ :outline_rows => {
17
+ :default => false,
18
+ :pat => FalseClass,
19
+ :desc => "group rows (default: no)",
20
+ },
16
21
  }
17
22
  end
18
23
 
@@ -43,6 +48,38 @@ module HTOTConv
43
48
  end
44
49
  end
45
50
 
51
+ if @option[:outline_rows]
52
+ outline_begin = Array.new(max_level, nil)
53
+ dummy_end_item = HTOTConv::Outline::Item.new(nil, 1, nil)
54
+ @data.item.concat([dummy_end_item]).each_with_index do |item, item_index|
55
+ (item.level..max_level).each do |level|
56
+ if outline_begin[level - 1]
57
+ if outline_begin[level - 1] < item_index - 1
58
+ ws.outline_level_rows((outline_begin[level - 1] + 1) + 1, (item_index - 1) + 1, level, false)
59
+ end
60
+ outline_begin[level - 1] = nil
61
+ end
62
+ end
63
+ outline_begin[item.level - 1] = item_index
64
+ end
65
+
66
+ # PR randym/axlsx#440 has been added to master branch
67
+ # https://github.com/randym/axlsx/commit/c80c8b9d9be5542471d66afcc2ce4ddd80cac1f7
68
+ # but latest release on rubygems does not contain this.
69
+ # So apply monkey patch to ws.sheet_pr.
70
+ if defined? ws.sheet_pr.outline_pr
71
+ ws.sheet_pr.outline_pr.summary_below = false
72
+ else
73
+ class << ws.sheet_pr # monkey patch
74
+ def to_xml_string(str="".dup)
75
+ tmp_str = "".dup
76
+ super(tmp_str)
77
+ str << tmp_str.sub('<pageSetUpPr', '<outlinePr summaryBelow="0" /><pageSetUpPr')
78
+ end
79
+ end
80
+ end
81
+ end
82
+
46
83
  case @option[:integrate_cells]
47
84
  when :colspan
48
85
  @data.item.each_with_index do |item, item_index|
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+ require 'axlsx'
3
+
4
+ require 'htot_conv/generator/base'
5
+
6
+ module HTOTConv
7
+ module Generator
8
+ class XlsxType3 < XlsxBase
9
+ def self.option_help
10
+ {
11
+ :integrate_cells => {
12
+ :default => nil,
13
+ :pat => [:colspan, :rowspan, :both],
14
+ :desc => "integrate key cells (specify 'colspan', 'rowspan' or 'both')",
15
+ },
16
+ }
17
+ end
18
+
19
+ def output_to_worksheet(ws)
20
+ max_level = @data.max_level
21
+ max_value_length = @data.max_value_length
22
+
23
+ ws.add_row([
24
+ @data.key_header[0],
25
+ *(HTOTConv::Util.pad_array([@data.value_header[0]], max_level)),
26
+ *((@data.value_header.length <= 1)? [] : @data.value_header.last(@data.value_header.length - 1)),
27
+ ], :style => Axlsx::STYLE_THIN_BORDER)
28
+ 1.upto(max_level) do |col_idx|
29
+ edges = [:top, :bottom]
30
+ edges << :left if (col_idx <= 1)
31
+ edges << :right if (col_idx >= max_level)
32
+ ws.rows.last.cells[col_idx].style = ws.styles.add_style(
33
+ :border => { :style => :thin, :color => "00", :edges => edges })
34
+ end
35
+
36
+ @data.item.each_with_index do |item, item_index|
37
+ key_value_cell = Array.new(max_level + 1, nil)
38
+ key_value_cell[item.level - 1] = item.key
39
+ key_value_cell[item.level ] = item.value[0]
40
+ rest_value_cell = (item.value.length <= 1)? [] :
41
+ HTOTConv::Util.pad_array(item.value.last(item.value.length - 1), max_value_length - 1)
42
+
43
+ ws.add_row(key_value_cell.concat(rest_value_cell),
44
+ :style => Axlsx::STYLE_THIN_BORDER)
45
+
46
+ 0.upto(max_level) do |col_idx|
47
+ edges = []
48
+
49
+ edges << :left if (col_idx <= item.level)
50
+ edges << :right if ((col_idx < item.level) || (col_idx >= max_level))
51
+ edges << :top if ((col_idx > (item.level - 2)) || (item_index == 0))
52
+ edges << :bottom if ((col_idx > (item.level - 1)) || (item_index == @data.item.length - 1))
53
+ ws.rows.last.cells[col_idx].style = ws.styles.add_style(
54
+ :border => { :style => :thin, :color => "00", :edges => edges })
55
+ end
56
+ end
57
+
58
+ if [:colspan, :both].include?(@option[:integrate_cells])
59
+ if max_level > 1
60
+ ws.merge_cells(ws.rows[0].cells[1..(max_level)])
61
+ end
62
+ @data.item.each_with_index do |item, item_index|
63
+ if item.level < max_level
64
+ ws.merge_cells(ws.rows[item_index + 1].cells[(item.level..max_level)])
65
+ end
66
+ end
67
+ end
68
+ if [:rowspan, :both].include?(@option[:integrate_cells])
69
+ @data.item.each_with_index do |item, item_index|
70
+ cells = [ws.rows[item_index + 1].cells[item.level - 1]]
71
+ ((item_index + 1)..(@data.item.length - 1)).each do |i|
72
+ break if @data.item[i].level <= item.level
73
+ cells << ws.rows[i + 1].cells[item.level - 1]
74
+ end
75
+
76
+ ws.merge_cells(cells) if cells.length > 1
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -11,7 +11,7 @@ module HTOTConv
11
11
  :integrate_cells => {
12
12
  :default => nil,
13
13
  :pat => [:colspan, :rowspan, :both],
14
- :desc => "integrate key cells (specify 'colspan', 'rowspan' or 'all')",
14
+ :desc => "integrate key cells (specify 'colspan', 'rowspan' or 'both')",
15
15
  },
16
16
  }
17
17
  end
@@ -2,6 +2,7 @@
2
2
  require 'htot_conv/generator/xlsx_type0.rb'
3
3
  require 'htot_conv/generator/xlsx_type1.rb'
4
4
  require 'htot_conv/generator/xlsx_type2.rb'
5
+ require 'htot_conv/generator/xlsx_type3.rb'
5
6
  require 'htot_conv/generator/xlsx_type4.rb'
6
7
  require 'htot_conv/generator/xlsx_type5.rb'
7
8
 
@@ -13,13 +13,22 @@ module HTOTConv
13
13
  @item << Item.new(*args)
14
14
  end
15
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
+
16
25
  def valid?
17
- @key_header.kind_of?(Array) &&
18
- @key_header.all? { |v| v.nil? || v.kind_of?(String) } &&
19
- @value_header.kind_of?(Array) &&
20
- @value_header.all? { |v| v.nil? || v.kind_of?(String) } &&
21
- @item.kind_of?(Array) &&
22
- @item.all? { |item| item.valid? }
26
+ begin
27
+ validate
28
+ true
29
+ rescue ValidationError
30
+ false
31
+ end
23
32
  end
24
33
 
25
34
  def max_level
@@ -62,12 +71,24 @@ module HTOTConv
62
71
  root
63
72
  end
64
73
 
74
+ class ValidationError < RuntimeError
75
+ end
76
+
65
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
+
66
85
  def valid?
67
- self.level.kind_of?(Numeric) &&
68
- (self.level > 0) &&
69
- (self.level.to_i == self.level) &&
70
- self.value.kind_of?(Array)
86
+ begin
87
+ validate
88
+ true
89
+ rescue ValidationError
90
+ false
91
+ end
71
92
  end
72
93
  end
73
94
 
@@ -0,0 +1,43 @@
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
+ :glob_pattern => {
10
+ :default => "**/*",
11
+ :pat => String,
12
+ :desc => "globbing pattern (default: \"**/*\")",
13
+ },
14
+ }
15
+ end
16
+
17
+ def parse(input=Dir.pwd)
18
+ outline = HTOTConv::Outline.new
19
+ outline.key_header = []
20
+ outline.value_header = []
21
+
22
+ outline_item = Set.new
23
+ Dir.chdir(input) do
24
+ Dir.glob(@option[:glob_pattern]).each do |f|
25
+ f.split(File::SEPARATOR).inject(nil) do |parent_path, v|
26
+ file_path = (parent_path)? File.join(parent_path, v) : v
27
+ outline_item << file_path
28
+ file_path
29
+ end
30
+ end
31
+ end
32
+
33
+ outline_item.sort.each do |file_path|
34
+ key = File.basename(file_path)
35
+ level = file_path.split(File::SEPARATOR).length
36
+ outline.add_item(key, level, [])
37
+ end
38
+
39
+ outline
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ require 'htot_conv/parser/base'
3
+
4
+ module HTOTConv
5
+ module Parser
6
+ class Opml < Base
7
+ def parse(input)
8
+ outline = HTOTConv::Outline.new
9
+ outline.key_header = []
10
+ outline.value_header = []
11
+
12
+ parser = Nokogiri::XML::SAX::Parser.new(ListDoc.new(outline))
13
+ parser.parse(input)
14
+
15
+ outline
16
+ end
17
+
18
+ class ListDoc < Nokogiri::XML::SAX::Document
19
+ def initialize(outline)
20
+ @outline = outline
21
+ @breadcrumb = []
22
+ end
23
+
24
+ def start_element(name, attrs=[])
25
+ if (name == "outline")
26
+ @breadcrumb << name
27
+ generate_outline_item(attrs)
28
+ end
29
+ end
30
+
31
+ def end_element(name)
32
+ @breadcrumb.pop if (name == "outline")
33
+ end
34
+
35
+ private
36
+ def generate_outline_item(attrs)
37
+ text = ""
38
+ level = @breadcrumb.length
39
+ values = []
40
+ attrs.each do |pair|
41
+ attr_name, attr_val = pair
42
+ if attr_name == "text"
43
+ text = attr_val
44
+ else
45
+ unless @outline.value_header.include?(attr_name)
46
+ @outline.value_header << attr_name
47
+ values[@outline.value_header.length - 1] = attr_val
48
+ else
49
+ values[@outline.value_header.index(attr_name)] = attr_val
50
+ end
51
+ end
52
+ end
53
+
54
+ @outline.add_item(text, level, values)
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -30,20 +30,20 @@ module HTOTConv
30
30
  end
31
31
 
32
32
  def parse(input)
33
- indent_regexp = Regexp.new("^(?<indents>(#{Regexp.escape(option[:indent])})*)")
34
- delimiter_regexp = (option[:delimiter].kind_of?(String))? Regexp.new(Regexp.escape(option[:delimiter])) : option[:delimiter]
33
+ indent_regexp = Regexp.new("^(?<indents>(#{Regexp.escape(@option[:indent])})*)")
34
+ delimiter_regexp = (@option[:delimiter].kind_of?(String))? Regexp.new(Regexp.escape(@option[:delimiter])) : @option[:delimiter]
35
35
  outline = HTOTConv::Outline.new
36
36
  outline.key_header = []
37
- outline.value_header = option[:value_header]
37
+ outline.value_header = @option[:value_header]
38
38
 
39
39
  input.each_line do |line|
40
- next if ((line.chomp == "") && (!option[:preserve_empty_line]))
40
+ next if ((line.chomp == "") && (!@option[:preserve_empty_line]))
41
41
 
42
42
  level = 1
43
43
  value = []
44
- if (option[:indent] || '').length > 0
44
+ if (@option[:indent] || '').length > 0
45
45
  indents = indent_regexp.match(line)[:indents]
46
- level = 1 + indents.length / option[:indent].length
46
+ level = 1 + indents.length / @option[:indent].length
47
47
  line = line.sub(indent_regexp, "")
48
48
  end
49
49
 
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  require 'htot_conv/parser/base.rb'
3
3
  require 'htot_conv/parser/simple_text.rb'
4
+ require 'htot_conv/parser/dir_tree.rb'
4
5
  require 'htot_conv/parser/html_list.rb'
6
+ require 'htot_conv/parser/opml.rb'
5
7
 
6
8
  module HTOTConv
7
9
  module Parser
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module HTOTConv
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: htot_conv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@cat_in_136"
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-10-01 00:00:00.000000000 Z
11
+ date: 2017-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: axlsx
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '5.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fakefs
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.11.3
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.11.3
83
97
  description: Convert from a simple hierarchical-tree outline text into ugly xlsx file
84
98
  email:
85
99
  - cat.in.136+github@gmail.com
@@ -105,12 +119,15 @@ files:
105
119
  - lib/htot_conv/generator/xlsx_type0.rb
106
120
  - lib/htot_conv/generator/xlsx_type1.rb
107
121
  - lib/htot_conv/generator/xlsx_type2.rb
122
+ - lib/htot_conv/generator/xlsx_type3.rb
108
123
  - lib/htot_conv/generator/xlsx_type4.rb
109
124
  - lib/htot_conv/generator/xlsx_type5.rb
110
125
  - lib/htot_conv/outline.rb
111
126
  - lib/htot_conv/parser.rb
112
127
  - lib/htot_conv/parser/base.rb
128
+ - lib/htot_conv/parser/dir_tree.rb
113
129
  - lib/htot_conv/parser/html_list.rb
130
+ - lib/htot_conv/parser/opml.rb
114
131
  - lib/htot_conv/parser/simple_text.rb
115
132
  - lib/htot_conv/util.rb
116
133
  - lib/htot_conv/version.rb