htot_conv 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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