csv_plus_plus 0.0.3 → 0.0.4

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
  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