csv_plus_plus 0.0.3 → 0.0.4

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
  SHA256:
3
- metadata.gz: 11364af3824cbfff63df10d7b932a6ad2c7a222e1a40b39f151af82a150d5dc4
4
- data.tar.gz: 2d6fe31ae0e6a7dee0c19f31b0328e1b20973541c6e2c12cb64f3fbf96d8fa02
3
+ metadata.gz: ea5b029c524b401348cc42399514c9fb689b13bfcf7298664429f69c85ae6607
4
+ data.tar.gz: 5bb79395742dcd89bf3b4ca7ede92a9a41a2c3ddefc4dff1b4232c285117373d
5
5
  SHA512:
6
- metadata.gz: 623953f6ff728e1dfc1f7f329dbc89e5ae7b7687cebd6da387ea36f0b0659020142e5f2029533e46964b8bf51c2f78b79634b9bb346cad6e6c96ae69d6737fb1
7
- data.tar.gz: 0604bc094e8d287bcec1390ff884786fe8dbf12b5e6e4ec4785cc9cef2297f92360a9a60809c855630edd5f633b2bc16bf378cb0c47a1be7eb2a7f70ae6beb7a
6
+ metadata.gz: 4a1bf4ccf98486b64ed69f34e701e9c4c69aea2b971c569aab7f6345ca721ccbde01570449033be23eeea37ec59d244dbb2692f27bfbfaae6069c84e23ea988a
7
+ data.tar.gz: 8cef1aa204255588787b3e3138ec282a9b45c174b83e647a91d0476aca199ee4ee8640f11c40418cded6026016a4383e1e1df7600cdfa5c5524d25a6c953fb76
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## v0.0.4
2
+
3
+ - Excel support
4
+
1
5
  ## v0.0.3
2
6
 
3
7
  - Fix the gem package to include the bin/ file
data/README.md CHANGED
@@ -9,7 +9,7 @@ A tool that allows you to programatically author spreadsheets in your favorite t
9
9
  A `csvpp` file consists of a (optional) code section and a CSV section separated by `---`. In the code section you can define variables and functions that can be used in the CSV below it. For example:
10
10
 
11
11
  ```
12
- fees := 0.65 # my broker charges $0.65 a trade
12
+ fees := 0.50 # my broker charges $0.50 a trade
13
13
 
14
14
  price := cellref(C)
15
15
  quantity := cellref(D)
data/bin/csv++ CHANGED
@@ -7,64 +7,18 @@ require_relative '../lib/csv_plus_plus'
7
7
  options = ::CSVPlusPlus::Options.new
8
8
 
9
9
  option_parser =
10
- # rubocop:disable Metrics/BlockLength
11
10
  ::OptionParser.new do |parser|
12
- parser.on('-b', '--backup', 'Create a backup of the spreadsheet before applying changes.') do
13
- options.backup = true
14
- end
15
-
16
- parser.on(
17
- '-g SHEET_ID',
18
- '--google-sheet-id SHEET_ID',
19
- 'The id of the sheet - you can extract this from the URL: ' \
20
- 'https://docs.google.com/spreadsheets/d/< ... SHEET_ID ... >/edit#gid=0'
21
- ) do |v|
22
- options.google_sheet_id = v
23
- end
24
-
25
- parser.on('-c', '--create', "Create the sheet if it doesn't exist. It will use --sheet-name if specified") do
26
- options.create_if_not_exists = true
27
- end
28
-
29
- parser.on(
30
- '-k KEY_VALUES',
31
- '--key-values KEY_VALUES',
32
- 'A comma-separated list of key=values which will be made available to the template'
33
- ) do |v|
34
- options.key_values =
35
- begin
36
- [v.split('=')].to_h
37
- rescue ::StandardError
38
- {}
39
- end
40
- end
41
-
42
- parser.on('-n SHEET_NAME', '--sheet-name SHEET_NAME', 'The name of the sheet to apply the template to') do |v|
43
- options.sheet_name = v
44
- end
45
-
46
- parser.on('-o OUTPUT_FILE', '--output OUTPUT_FILE', 'The file to write to (must be .csv, .ods, .xls)') do |v|
47
- options.output_filename = v
48
- end
49
-
50
- parser.on('-v', '--verbose', 'Enable verbose output') do
51
- options.verbose = true
52
- end
53
-
54
- parser.on('-x OFFSET', '--offset-columns OFFSET', 'Apply the template offset by OFFSET cells') do |v|
55
- options.offset[0] = v
56
- end
57
-
58
- parser.on('-y OFFSET', '--offset-rows OFFSET', 'Apply the template offset by OFFSET rows') do |v|
59
- options.offset[1] = v
60
- end
61
-
62
11
  parser.on('-h', '--help', 'Show help information') do
63
12
  puts(parser)
64
13
  exit
65
14
  end
15
+
16
+ ::SUPPORTED_CSVPP_FLAGS.each do |flag|
17
+ parser.on(flag.short_flag, flag.long_flag, flag.description) do |v|
18
+ flag.handler.call(options, v)
19
+ end
20
+ end
66
21
  end
67
- # rubocop:enable Metrics/BlockLength
68
22
 
69
23
  option_parser.parse!
70
24
 
@@ -77,7 +31,12 @@ end
77
31
 
78
32
  begin
79
33
  ::CSVPlusPlus.apply_template_to_sheet!(::ARGF.read, ::ARGF.filename, options)
80
- rescue ::CSVPlusPlus::Language::SyntaxError => e
81
- warn(options.verbose ? e.to_verbose_trace : e.to_trace)
34
+ rescue ::CSVPlusPlus::Error => e
35
+ if e.is_a?(::CSVPlusPlus::Language::SyntaxError)
36
+ warn(options.verbose ? e.to_verbose_trace : e.to_trace)
37
+ else
38
+ warn(e.message)
39
+ end
40
+
82
41
  exit(1)
83
42
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './google_options'
4
+
5
+ module CSVPlusPlus
6
+ # Individual CLI flags that a user can supply
7
+ class CliFlag
8
+ attr_reader :short_flag, :long_flag, :description, :handler
9
+
10
+ # initialize
11
+ def initialize(short_flag, long_flag, description, handler)
12
+ @short_flag = short_flag
13
+ @long_flag = long_flag
14
+ @description = description
15
+ @handler = handler
16
+ end
17
+
18
+ # to_s
19
+ def to_s
20
+ "#{@short_flag}, #{@long_flag} #{@description}"
21
+ end
22
+ end
23
+ end
24
+
25
+ SUPPORTED_CSVPP_FLAGS = [
26
+ ::CSVPlusPlus::CliFlag.new(
27
+ '-b',
28
+ '--backup',
29
+ 'Create a backup of the spreadsheet before applying changes.',
30
+ ->(options, _v) { options.backup = true }
31
+ ),
32
+ ::CSVPlusPlus::CliFlag.new(
33
+ '-c',
34
+ '--create',
35
+ "Create the sheet if it doesn't exist. It will use --sheet-name if specified",
36
+ ->(options, _v) { options.create_if_not_exists = true }
37
+ ),
38
+ ::CSVPlusPlus::CliFlag.new(
39
+ '-g SHEET_ID',
40
+ '--google-sheet-id SHEET_ID',
41
+ 'The id of the sheet - you can extract this from the URL: ' \
42
+ 'https://docs.google.com/spreadsheets/d/< ... SHEET_ID ... >/edit#gid=0',
43
+ ->(options, v) { options.google_sheet_id = v }
44
+ ),
45
+ ::CSVPlusPlus::CliFlag.new(
46
+ '-k',
47
+ '--key-values KEY_VALUES',
48
+ 'A comma-separated list of key=values which will be made available to the template',
49
+ lambda do |options, v|
50
+ options.key_values =
51
+ begin
52
+ [v.split('=')].to_h
53
+ rescue ::StandardError
54
+ {}
55
+ end
56
+ end
57
+ ),
58
+ ::CSVPlusPlus::CliFlag.new(
59
+ '-n SHEET_NAME',
60
+ '--sheet-name SHEET_NAME',
61
+ 'The name of the sheet to apply the template to',
62
+ ->(options, v) { options.sheet_name = v }
63
+ ),
64
+ ::CSVPlusPlus::CliFlag.new(
65
+ '-o OUTPUT_FILE',
66
+ '--output OUTPUT_FILE',
67
+ 'The file to write to (must be .csv, .ods, .xls)',
68
+ ->(options, v) { options.output_filename = v }
69
+ ),
70
+ ::CSVPlusPlus::CliFlag.new('-v', '--verbose', 'Enable verbose output', ->(options, _v) { options.verbose = true }),
71
+ ::CSVPlusPlus::CliFlag.new(
72
+ '-x OFFSET',
73
+ '--offset-columns OFFSET',
74
+ 'Apply the template offset by OFFSET cells',
75
+ ->(options, v) { options.offset[0] = v }
76
+ ),
77
+ ::CSVPlusPlus::CliFlag.new(
78
+ '-y OFFSET',
79
+ '--offset-rows OFFSET',
80
+ 'Apply the template offset by OFFSET rows',
81
+ ->(options, v) { options.offset[1] = v }
82
+ )
83
+ ].freeze
@@ -3,20 +3,54 @@
3
3
  module CSVPlusPlus
4
4
  # A color value
5
5
  class Color
6
- attr_reader :red, :green, :blue
6
+ attr_reader :red_hex, :green_hex, :blue_hex
7
7
 
8
8
  # create an instance from a string like "#FFF" or "#FFFFFF"
9
9
  def initialize(hex_string)
10
- @red, @green, @blue =
11
- hex_string
12
- .gsub(/^#?/, '')
13
- .match(/(\w\w?)(\w\w?)(\w\w?)/)
14
- .captures
15
- .map do |s|
16
- 255 / (s.length == 2 ? s : s + s).to_i(16)
17
- rescue ::StandardError
18
- 0
19
- end
10
+ @red_hex, @green_hex, @blue_hex = hex_string
11
+ .gsub(/^#?/, '')
12
+ .match(/([0-9a-f]{1,2})([0-9a-f]{1,2})([0-9a-f]{1,2})/i)
13
+ &.captures
14
+ &.map { |s| s.length == 1 ? s + s : s }
15
+ end
16
+
17
+ # The percent (decimal between 0-1) of red
18
+ def red_percent
19
+ hex_to_percent(@red_hex)
20
+ end
21
+
22
+ # The percent (decimal between 0-1) of green
23
+ def green_percent
24
+ hex_to_percent(@green_hex)
25
+ end
26
+
27
+ # The percent (decimal between 0-1) of blue
28
+ def blue_percent
29
+ hex_to_percent(@blue_hex)
30
+ end
31
+
32
+ # to_hex
33
+ def to_hex
34
+ [@red_hex, @green_hex, @blue_hex].join
35
+ end
36
+
37
+ # to_s
38
+ def to_s
39
+ "Color(r: #{@red_hex}, g: #{@green_hex}, b: #{@blue_hex})"
40
+ end
41
+
42
+ # ==
43
+ def ==(other)
44
+ other.is_a?(self.class) &&
45
+ other.red_hex == @red_hex &&
46
+ other.green_hex == @green_hex &&
47
+ other.blue_hex == @blue_hex
48
+ end
49
+
50
+ private
51
+
52
+ def hex_to_percent(hex)
53
+ hex.to_i(16) / 255
20
54
  end
21
55
  end
22
56
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CSVPlusPlus
4
+ # An error thrown by our code (generally to be handled at the top level bin/ command)
5
+ class Error < StandardError
6
+ end
7
+ end
@@ -54,11 +54,6 @@ module CSVPlusPlus
54
54
  include ::TSort
55
55
  alias tsort_each_node each_key
56
56
 
57
- # create a +DependencyGraph+ from a +Hash+
58
- def self.from_hash(hash)
59
- self[hash.map { |k, v| [k, v] }]
60
- end
61
-
62
57
  # sort each child
63
58
  def tsort_each_child(node, &)
64
59
  fetch(node).each(&)
@@ -14,7 +14,6 @@ require_relative 'scope'
14
14
 
15
15
  module CSVPlusPlus
16
16
  module Language
17
- ##
18
17
  # Encapsulates the parsing and building of objects (+Template+ -> +Row+ -> +Cell+).
19
18
  # Variable resolution is delegated to the +Scope+
20
19
  # rubocop:disable Metrics/ClassLength
@@ -127,8 +127,6 @@ module CSVPlusPlus
127
127
 
128
128
  # this will throw a syntax error if it doesn't exist (which is what we want)
129
129
  return ::BUILTIN_FUNCTIONS[id] if ::BUILTIN_FUNCTIONS.key?(id)
130
-
131
- @runtime.raise_syntax_error('Unknown function', fn_id)
132
130
  end
133
131
 
134
132
  def apply_arguments(function, function_call)
@@ -4,7 +4,7 @@ module CSVPlusPlus
4
4
  module Language
5
5
  ##
6
6
  # An error that can be thrown for various syntax errors
7
- class SyntaxError < StandardError
7
+ class SyntaxError < ::CSVPlusPlus::Error
8
8
  # initialize
9
9
  def initialize(message, bad_input, runtime, wrapped_error: nil)
10
10
  @bad_input = bad_input.to_s
@@ -6,32 +6,20 @@ require_relative './expand'
6
6
  require_relative './language/syntax_error'
7
7
 
8
8
  module CSVPlusPlus
9
- ##
10
9
  # A container representing the operations that can be applied to a cell or row
11
10
  class Modifier
12
11
  attr_reader :bordercolor, :borders, :color, :fontcolor, :formats
13
12
  attr_writer :borderstyle
14
- attr_accessor :expand, :fontfamily, :fontsize, :note, :numberformat, :row_level, :validation
13
+ attr_accessor :expand, :fontfamily, :fontsize, :halign, :valign, :note, :numberformat, :row_level, :validation
15
14
 
16
15
  # initialize
17
16
  def initialize(row_level: false)
18
17
  @row_level = row_level
19
18
  @freeze = false
20
- @align = ::Set.new
21
19
  @borders = ::Set.new
22
20
  @formats = ::Set.new
23
21
  end
24
22
 
25
- # Set an align format. +direction+ must be 'center', 'left', 'right', 'bottom'
26
- def align=(direction)
27
- @align << direction
28
- end
29
-
30
- # Is it aligned to a given direction?
31
- def aligned?(direction)
32
- @align.include?(direction)
33
- end
34
-
35
23
  # Set the color. hex_value is a String
36
24
  def color=(hex_value)
37
25
  @color = ::CSVPlusPlus::Color.new(hex_value)
@@ -110,12 +98,13 @@ module CSVPlusPlus
110
98
  # to_s
111
99
  def to_s
112
100
  # TODO... I dunno, not sure how to manage this
113
- "Modifier(row_level: #{@row_level} align: #{@align} format: #{@formats} font_size: #{@font_size})"
101
+ "Modifier(row_level: #{@row_level} halign: #{@halign} valign: #{@valign} format: #{@formats} " \
102
+ "font_size: #{@font_size})"
114
103
  end
115
104
 
116
105
  # Create a new modifier instance, with all values defaulted from +other+
117
106
  def take_defaults_from!(other)
118
- instance_variables.each do |property|
107
+ other.instance_variables.each do |property|
119
108
  value = other.instance_variable_get(property)
120
109
  instance_variable_set(property, value.clone)
121
110
  end