csv_plus_plus 0.0.4 → 0.0.5

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: ea5b029c524b401348cc42399514c9fb689b13bfcf7298664429f69c85ae6607
4
- data.tar.gz: 5bb79395742dcd89bf3b4ca7ede92a9a41a2c3ddefc4dff1b4232c285117373d
3
+ metadata.gz: c4f5c9b5a342102fa8e1c31b319fb05f19ad55278bc633435129254b5b2511a8
4
+ data.tar.gz: 0c2656d4d7b22d0b3b3311745ed5a70b789277c622f0f2d09d2b8a144de71a8d
5
5
  SHA512:
6
- metadata.gz: 4a1bf4ccf98486b64ed69f34e701e9c4c69aea2b971c569aab7f6345ca721ccbde01570449033be23eeea37ec59d244dbb2692f27bfbfaae6069c84e23ea988a
7
- data.tar.gz: 8cef1aa204255588787b3e3138ec282a9b45c174b83e647a91d0476aca199ee4ee8640f11c40418cded6026016a4383e1e1df7600cdfa5c5524d25a6c953fb76
6
+ metadata.gz: 90965e2275cc7988f4054b59e30523cd645b21c1adb89797828e86a767217b09ac174bbc17094604dd608b93defd79f4c9a74ccf7e2f20dd17995f8c1b5dadac
7
+ data.tar.gz: 291011896232e88a7bd0e252887459986812d2877c1d0383458250e1c30cf735d8b2bdaf5dd759f44fa5b8b33b08f74d780df7960622ab774e9f6d856628508f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## v0.0.5
2
+
3
+ - Support the --backup/-b option
4
+ - bin/csvpp (which does the same thing as bin/csv++ but will work better on other filesystems)
5
+ - Fix links in gemspec (which end up on rubygems.org)
6
+ - docs & tests
7
+
1
8
  ## v0.0.4
2
9
 
3
10
  - Excel support
data/README.md CHANGED
@@ -21,12 +21,17 @@ def profit() (price * quantity) - fees
21
21
  ![[expand]],[[format=bold]],,,"=PROFIT()",$$fees
22
22
  ```
23
23
 
24
- ## Predefined Variables
24
+ ## Variables
25
25
 
26
- * `$$rownum` - The current row number. The first row of the spreadsheet starts at 1
26
+ Variables can be defined in the code section by giving a name (a combination of letters, numbers and underscores ) the expression `:=` and followed with a value.
27
27
 
28
- ## Predefined Functions
28
+ ### Built-in Variables
29
29
 
30
+ * `$$rownum` - The current row number. The first row of the spreadsheet starts at 1. Can be used anywhere and it's value will evaluate to the current row being processed.
31
+
32
+ ## Functions
33
+
34
+ ### Built-in Functions
30
35
  * `cellref(CELL)` - Returns a reference to the `CELL` relative to the current row. If the current `$$rownum` is `2`, then `CELLREF("C")` returns a reference to cell `C2`.
31
36
 
32
37
  ## Modifiers
data/bin/csv++ CHANGED
@@ -1,42 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'optparse'
5
4
  require_relative '../lib/csv_plus_plus'
6
5
 
7
- options = ::CSVPlusPlus::Options.new
8
-
9
- option_parser =
10
- ::OptionParser.new do |parser|
11
- parser.on('-h', '--help', 'Show help information') do
12
- puts(parser)
13
- exit
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
21
- end
22
-
23
- option_parser.parse!
24
-
25
- error_message = options.validate
26
- unless error_message.nil?
27
- warn(error_message)
28
- puts(option_parser)
29
- exit(1)
30
- end
31
-
32
- begin
33
- ::CSVPlusPlus.apply_template_to_sheet!(::ARGF.read, ::ARGF.filename, options)
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
-
41
- exit(1)
42
- end
6
+ ::CSVPlusPlus::CLI.launch_compiler!
data/bin/csvpp ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/csv_plus_plus'
5
+
6
+ ::CSVPlusPlus::CLI.launch_compiler!
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ module CSVPlusPlus
6
+ # Handle running the application with the given CLI flags
7
+ class CLI
8
+ # handle any CLI flags and launch the compiler
9
+ def self.launch_compiler!
10
+ cli = new
11
+ cli.compile!
12
+ rescue ::StandardError => e
13
+ cli.handle_error(e)
14
+ exit(1)
15
+ end
16
+
17
+ # initialize
18
+ def initialize
19
+ parse_options!
20
+ end
21
+
22
+ # compile the given template, using the given CLI flags
23
+ def compile!
24
+ ::CSVPlusPlus.apply_template_to_sheet!(::ARGF.read, ::ARGF.filename, @options)
25
+ end
26
+
27
+ # (nicely) handle a given error. how it's handled depends on if it's our error and if @options.verbose
28
+ def handle_error(error)
29
+ case error
30
+ when ::CSVPlusPlus::Error
31
+ handle_internal_error(error)
32
+ when ::Google::Apis::ClientError
33
+ handle_google_error(error)
34
+ else
35
+ # TODO: more if verbose?
36
+ warn(error.message)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def handle_internal_error(error)
43
+ if error.is_a?(::CSVPlusPlus::Language::SyntaxError)
44
+ warn(@options.verbose ? error.to_verbose_trace : error.to_trace)
45
+ else
46
+ warn(error.message)
47
+ end
48
+ end
49
+
50
+ def handle_google_error(error)
51
+ warn("Error making Google Sheets API request: #{error.message}")
52
+ return unless @options.verbose
53
+
54
+ warn("#{error.status_code} Error making Google API request [#{error.message}]: #{error.body}")
55
+ end
56
+
57
+ def parse_options!
58
+ @options = ::CSVPlusPlus::Options.new
59
+ option_parser.parse!
60
+ validate_options
61
+ end
62
+
63
+ def validate_options
64
+ error_message = @options.validate
65
+ return if error_message.nil?
66
+
67
+ puts(option_parser)
68
+ raise(::CSVPlusPlus::Error, error_message)
69
+ end
70
+
71
+ def option_parser
72
+ ::OptionParser.new do |parser|
73
+ parser.on('-h', '--help', 'Show help information') do
74
+ puts(parser)
75
+ exit
76
+ end
77
+
78
+ ::SUPPORTED_CSVPP_FLAGS.each do |f|
79
+ parser.on(f.short_flag, f.long_flag, f.description) { |v| f.handler.call(@options, v) }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CSVPlusPlus
4
+ # A convenience wrapper around Google's REST API client
5
+ module GoogleApiClient
6
+ # Get a +::Google::Apis::SheetsV4::SheetsService+ instance connected to the sheets API
7
+ def self.sheets_client
8
+ ::Google::Apis::SheetsV4::SheetsService.new.tap do |s|
9
+ s.authorization = ::Google::Auth.get_application_default(['https://www.googleapis.com/auth/spreadsheets'].freeze)
10
+ end
11
+ end
12
+
13
+ # Get a +::Google::Apis::DriveV3::DriveService+ instance connected to the drive API
14
+ def self.drive_client
15
+ ::Google::Apis::DriveV3::DriveService.new.tap do |d|
16
+ d.authorization = ::Google::Auth.get_application_default(['https://www.googleapis.com/auth/drive.file'].freeze)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -5,24 +5,24 @@ require_relative './entity'
5
5
  module CSVPlusPlus
6
6
  module Language
7
7
  module Entities
8
- ##
9
8
  # A boolean value
10
9
  class Boolean < Entity
11
10
  attr_reader :value
12
11
 
13
12
  # initialize
13
+ # @param value [String, Boolean]
14
14
  def initialize(value)
15
15
  super(:boolean)
16
16
  # TODO: probably can do a lot better in general on type validation
17
17
  @value = value.is_a?(::String) ? (value.downcase == 'true') : value
18
18
  end
19
19
 
20
- # to_s
20
+ # @return [String]
21
21
  def to_s
22
22
  @value.to_s.upcase
23
23
  end
24
24
 
25
- # ==
25
+ # @return [Boolean]
26
26
  def ==(other)
27
27
  super && value == other.value
28
28
  end
@@ -9,13 +9,14 @@ module CSVPlusPlus
9
9
  class Entity
10
10
  attr_reader :id, :type
11
11
 
12
- # initialize
12
+ # @param type [String, Symbol]
13
+ # @param id [String]
13
14
  def initialize(type, id: nil)
14
15
  @type = type.to_sym
15
16
  @id = id.downcase.to_sym if id
16
17
  end
17
18
 
18
- # ==
19
+ # @return [Boolean]
19
20
  def ==(other)
20
21
  self.class == other.class && @type == other.type && @id == other.id
21
22
  end
@@ -30,7 +31,8 @@ module CSVPlusPlus
30
31
  end
31
32
  end
32
33
 
33
- # support predicates by type
34
+ # Respond to predicates by type (entity.boolean?, entity.string?, etc)
35
+ # @return [Boolean]
34
36
  def respond_to_missing?(method_name, *_arguments)
35
37
  (method_name =~ /^(\w+)\?$/ && a_type?(::Regexp.last_match(1))) || super
36
38
  end
@@ -42,17 +44,19 @@ module CSVPlusPlus
42
44
  end
43
45
  end
44
46
 
45
- # An entity that can take arguments
47
+ # An entity that can take other entities as arguments
46
48
  class EntityWithArguments < Entity
47
49
  attr_reader :arguments
48
50
 
49
- # initialize
51
+ # @param type [String, Symbol]
52
+ # @param id [String]
53
+ # @param arguments [Array<Entity>]
50
54
  def initialize(type, id: nil, arguments: [])
51
55
  super(type, id:)
52
56
  @arguments = arguments
53
57
  end
54
58
 
55
- # ==
59
+ # @return [Boolean]
56
60
  def ==(other)
57
61
  super && @arguments == other.arguments
58
62
  end
@@ -7,12 +7,30 @@ require_relative './language/syntax_error'
7
7
 
8
8
  module CSVPlusPlus
9
9
  # A container representing the operations that can be applied to a cell or row
10
+ #
11
+ # @attr expand [Expand]
12
+ # @attr fontfamily [String]
13
+ # @attr fontsize [String]
14
+ # @attr halign ['left', 'center', 'right']
15
+ # @attr valign ['top', 'center', 'bottom']
16
+ # @attr note [String]
17
+ # @attr numberformat [String]
18
+ # @attr row_level [Boolean]
19
+ # @attr validation [Object]
20
+ #
21
+ # @attr_writer borderstyle [String]
22
+ #
23
+ # @attr_reader bordercolor [String]
24
+ # @attr_reader borders [Array<String>]
25
+ # @attr_reader color [Color]
26
+ # @attr_reader fontcolor [Color]
27
+ # @attr_reader formats [Array<String>]
10
28
  class Modifier
11
29
  attr_reader :bordercolor, :borders, :color, :fontcolor, :formats
12
30
  attr_writer :borderstyle
13
31
  attr_accessor :expand, :fontfamily, :fontsize, :halign, :valign, :note, :numberformat, :row_level, :validation
14
32
 
15
- # initialize
33
+ # @param row_level [Boolean] Whether or not this modifier applies to the entire row
16
34
  def initialize(row_level: false)
17
35
  @row_level = row_level
18
36
  @freeze = false
@@ -20,47 +38,59 @@ module CSVPlusPlus
20
38
  @formats = ::Set.new
21
39
  end
22
40
 
23
- # Set the color. hex_value is a String
41
+ # Set the color
42
+ # @param hex_value [String]
24
43
  def color=(hex_value)
25
44
  @color = ::CSVPlusPlus::Color.new(hex_value)
26
45
  end
27
46
 
28
- # Assign a border. +side+ must be 'top', 'left', 'bottom', 'right' or 'all'
47
+ # Assign a border
48
+ # @param side ['top', 'left', 'bottom', 'right', 'all']
29
49
  def border=(side)
30
50
  @borders << side
31
51
  end
32
52
 
33
53
  # Does this have a border along +side+?
54
+ # @param side ['top', 'left', 'bottom', 'right', 'all']
55
+ # @return [Boolean]
34
56
  def border_along?(side)
35
- border_all? || @borders.include?(side)
57
+ @borders.include?('all') || @borders.include?(side)
36
58
  end
37
59
 
38
60
  # Does this have a border along all sides?
61
+ # @return [Boolean]
39
62
  def border_all?
40
- @borders.include?('all')
63
+ @borders.include?('all') \
64
+ || (border_along?('top') && border_along?('bottom') && border_along?('left') && border_along?('right'))
41
65
  end
42
66
 
43
67
  # Set the bordercolor
68
+ # @param hex_value [String] formatted as '#000000', '#000' or '000000'
44
69
  def bordercolor=(hex_value)
45
70
  @bordercolor = ::CSVPlusPlus::Color.new(hex_value)
46
71
  end
47
72
 
48
73
  # Are there any borders set?
74
+ # @return [Boolean]
49
75
  def any_border?
50
76
  !@borders.empty?
51
77
  end
52
78
 
53
79
  # Set the fontcolor
80
+ # @param hex_value [String] formatted as '#000000', '#000' or '000000'
54
81
  def fontcolor=(hex_value)
55
82
  @fontcolor = ::CSVPlusPlus::Color.new(hex_value)
56
83
  end
57
84
 
58
- # Set a format. +type+ must be 'bold', 'italic', 'underline' or 'strikethrough'
85
+ # Set a text format (bolid, italic, underline or strikethrough)
86
+ # @param value ['bold', 'italic', 'underline', 'strikethrough']
59
87
  def format=(value)
60
88
  @formats << value
61
89
  end
62
90
 
63
91
  # Is the given format set?
92
+ # @param type ['bold', 'italic', 'underline', 'strikethrough']
93
+ # @return [Boolean]
64
94
  def formatted?(type)
65
95
  @formats.include?(type)
66
96
  end
@@ -71,6 +101,7 @@ module CSVPlusPlus
71
101
  end
72
102
 
73
103
  # Is the row forzen?
104
+ # @return [Boolean]
74
105
  def frozen?
75
106
  @frozen
76
107
  end
@@ -81,21 +112,24 @@ module CSVPlusPlus
81
112
  end
82
113
 
83
114
  # Is this a row-level modifier?
115
+ # @return [Boolean]
84
116
  def row_level?
85
117
  @row_level
86
118
  end
87
119
 
88
120
  # Is this a cell-level modifier?
121
+ # @return [Boolean]
89
122
  def cell_level?
90
123
  !@row_level
91
124
  end
92
125
 
93
126
  # Style of border
127
+ # @return [String]
94
128
  def borderstyle
95
129
  @borderstyle || 'solid'
96
130
  end
97
131
 
98
- # to_s
132
+ # @return [String]
99
133
  def to_s
100
134
  # TODO... I dunno, not sure how to manage this
101
135
  "Modifier(row_level: #{@row_level} halign: #{@halign} valign: #{@valign} format: #{@formats} " \
@@ -103,8 +137,12 @@ module CSVPlusPlus
103
137
  end
104
138
 
105
139
  # Create a new modifier instance, with all values defaulted from +other+
140
+ # @param other [Modifier]
106
141
  def take_defaults_from!(other)
107
142
  other.instance_variables.each do |property|
143
+ # don't propagate row-specific values
144
+ next if property == :@row_level
145
+
108
146
  value = other.instance_variable_get(property)
109
147
  instance_variable_set(property, value.clone)
110
148
  end
@@ -15,7 +15,6 @@ module CSVPlusPlus
15
15
  @create_if_not_exists = false
16
16
  @key_values = {}
17
17
  @verbose = false
18
- # TODO: switch to true? probably a safer choice
19
18
  @backup = false
20
19
  end
21
20
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CSVPlusPlus
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  public_constant :VERSION
6
6
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  module CSVPlusPlus
4
4
  module Writer
5
- ##
6
5
  # Some shared functionality that all Writers should build on
7
6
  class BaseWriter
8
7
  attr_accessor :options
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './file_backer_upper'
4
+
3
5
  module CSVPlusPlus
4
6
  module Writer
5
- ##
6
7
  # A class that can output a +Template+ to CSV
7
8
  class CSV < ::CSVPlusPlus::Writer::BaseWriter
9
+ include ::CSVPlusPlus::Writer::FileBackerUpper
10
+
8
11
  # write a +template+ to CSV
9
12
  def write(template)
10
13
  # TODO: also read it and merge the results
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './file_backer_upper'
3
4
  require_relative './rubyxl_builder'
4
5
 
5
6
  module CSVPlusPlus
6
7
  module Writer
7
8
  # A class that can output a +Template+ to an Excel file
8
9
  class Excel < ::CSVPlusPlus::Writer::BaseWriter
10
+ include ::CSVPlusPlus::Writer::FileBackerUpper
11
+
9
12
  # write the +template+ to an Excel file
10
13
  def write(template)
11
14
  ::CSVPlusPlus::Writer::RubyXLBuilder.new(
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'pathname'
5
+
6
+ module CSVPlusPlus
7
+ module Writer
8
+ # A mixin that can
9
+ module FileBackerUpper
10
+ # we don't want to include a bunch of second/millisecond stuff in the filename unless we
11
+ # really need to. so try a less specifically formatted filename then get more specific
12
+ DESIRED_BACKUP_FORMATS = [%(%Y_%m_%d-%I_%M%p), %(%Y_%m_%d-%I_%M_%S%p), %(%Y_%m_%d-%I_%M_%S_%L%p)].freeze
13
+ private_constant :DESIRED_BACKUP_FORMATS
14
+
15
+ # Assuming the underlying spreadsheet is file-based, create a backup of it
16
+ # rubocop:disable Metrics/MethodLength
17
+ def write_backup
18
+ return unless ::File.exist?(@options.output_filename)
19
+
20
+ attempted = []
21
+ backed_up_to = nil
22
+
23
+ # rubocop:disable Lint/ConstantResolution
24
+ DESIRED_BACKUP_FORMATS.find do |file_format|
25
+ # rubocop:enable Lint/ConstantResolution
26
+ filename = format_backup_filename(file_format)
27
+ attempted << filename
28
+ backed_up_to = backup(filename)
29
+
30
+ break if backed_up_to
31
+ end
32
+
33
+ unless backed_up_to
34
+ raise(::CSVPlusPlus::Error, "Unable to write backup file despite trying these: #{attempted.join(', ')}")
35
+ end
36
+
37
+ warn("Backed up #{@options.output_filename} to #{backed_up_to}") if @options.verbose
38
+ end
39
+ # rubocop:enable Metrics/MethodLength
40
+
41
+ private
42
+
43
+ def backup(filename)
44
+ return if ::File.exist?(filename)
45
+
46
+ ::FileUtils.cp(@options.output_filename, filename)
47
+ filename
48
+ end
49
+
50
+ def format_backup_filename(file_format)
51
+ pn = ::Pathname.new(@options.output_filename)
52
+ pn.sub_ext("-#{::Time.now.strftime(file_format)}" + pn.extname)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../google_api_client'
3
4
  require_relative 'base_writer'
4
5
  require_relative 'google_sheet_builder'
5
6
 
6
- AUTH_SCOPES = ['https://www.googleapis.com/auth/spreadsheets'].freeze
7
- FULL_RANGE = 'A1:Z1000'
8
-
9
7
  module CSVPlusPlus
10
8
  module Writer
11
- # A class that can output a +Template+ to Google Sheets (via their API)
9
+ # A class that can write a +Template+ to Google Sheets (via their API)
12
10
  class GoogleSheets < ::CSVPlusPlus::Writer::BaseWriter
13
- # XXX it would be nice to raise this but we shouldn't expand out more than necessary for our data
11
+ # TODO: it would be nice to raise this but we shouldn't expand out more than necessary for our data
14
12
  SPREADSHEET_INFINITY = 1000
15
13
  public_constant :SPREADSHEET_INFINITY
16
14
 
@@ -24,7 +22,7 @@ module CSVPlusPlus
24
22
 
25
23
  # write a +template+ to Google Sheets
26
24
  def write(template)
27
- auth!
25
+ @sheets_client = ::CSVPlusPlus::GoogleApiClient.sheets_client
28
26
 
29
27
  fetch_spreadsheet!
30
28
  fetch_spreadsheet_values!
@@ -32,13 +30,18 @@ module CSVPlusPlus
32
30
  create_sheet! if @options.create_if_not_exists
33
31
 
34
32
  update_cells!(template)
35
- rescue ::Google::Apis::ClientError => e
36
- handle_google_error(e)
33
+ end
34
+
35
+ # write a backup of the google sheet
36
+ def write_backup
37
+ drive_client = ::CSVPlusPlus::GoogleApiClient.drive_client
38
+ drive_client.copy_file(@sheet_id)
37
39
  end
38
40
 
39
41
  protected
40
42
 
41
43
  def load_requires
44
+ require('google/apis/drive_v3')
42
45
  require('google/apis/sheets_v4')
43
46
  require('googleauth')
44
47
  end
@@ -50,12 +53,7 @@ module CSVPlusPlus
50
53
  end
51
54
 
52
55
  def full_range
53
- format_range(::FULL_RANGE)
54
- end
55
-
56
- def auth!
57
- @gs ||= sheets_ns::SheetsService.new
58
- @gs.authorization = ::Google::Auth.get_application_default(::AUTH_SCOPES)
56
+ format_range('A1:Z1000')
59
57
  end
60
58
 
61
59
  def fetch_spreadsheet_values!
@@ -85,7 +83,7 @@ module CSVPlusPlus
85
83
  end
86
84
 
87
85
  def get_all_spreadsheet_values(render_option)
88
- @gs.get_spreadsheet_values(@sheet_id, full_range, value_render_option: render_option)
86
+ @sheets_client.get_spreadsheet_values(@sheet_id, full_range, value_render_option: render_option)
89
87
  end
90
88
 
91
89
  def sheet
@@ -95,7 +93,7 @@ module CSVPlusPlus
95
93
  end
96
94
 
97
95
  def fetch_spreadsheet!
98
- @spreadsheet = @gs.get_spreadsheet(@sheet_id)
96
+ @spreadsheet = @sheets_client.get_spreadsheet(@sheet_id)
99
97
 
100
98
  return unless @sheet_name.nil?
101
99
 
@@ -105,34 +103,23 @@ module CSVPlusPlus
105
103
  def create_sheet!
106
104
  return if sheet
107
105
 
108
- @gs.create_spreadsheet(@sheet_name)
109
- get_spreadsheet!
106
+ @sheets_client.create_spreadsheet(@sheet_name)
107
+ fetch_spreadsheet!
110
108
  @sheet_name = @spreadsheet.sheets.last.properties.title
111
109
  end
112
110
 
113
111
  def update_cells!(template)
114
- builder = ::CSVPlusPlus::Writer::GoogleSheetBuilder.new(
112
+ @sheets_client.batch_update_spreadsheet(@sheet_id, builder(template).batch_update_spreadsheet_request)
113
+ end
114
+
115
+ def builder(template)
116
+ ::CSVPlusPlus::Writer::GoogleSheetBuilder.new(
115
117
  rows: template.rows,
116
118
  sheet_id: sheet&.properties&.sheet_id,
117
119
  column_index: @options.offset[1],
118
120
  row_index: @options.offset[0],
119
121
  current_sheet_values: @current_sheet_values
120
122
  )
121
- @gs.batch_update_spreadsheet(@sheet_id, builder.batch_update_spreadsheet_request)
122
- rescue ::Google::Apis::ClientError => e
123
- handle_google_error(e)
124
- end
125
-
126
- def sheets_ns
127
- ::Google::Apis::SheetsV4
128
- end
129
-
130
- def handle_google_error(error)
131
- if @options.verbose
132
- warn("#{error.status_code} Error making Google Sheets API request [#{error.message}]: #{error.body}")
133
- else
134
- warn("Error making Google Sheets API request: #{error.message}")
135
- end
136
123
  end
137
124
  end
138
125
  end
data/lib/csv_plus_plus.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'csv_plus_plus/cli'
3
4
  require_relative 'csv_plus_plus/error'
4
5
  require_relative 'csv_plus_plus/language/compiler'
5
6
  require_relative 'csv_plus_plus/options'
@@ -15,7 +16,10 @@ module CSVPlusPlus
15
16
  template = c.parse_template
16
17
 
17
18
  output = ::CSVPlusPlus::Writer.writer(options)
18
- c.outputting! { output.write(template) }
19
+ c.outputting! do
20
+ output.write_backup if options.backup
21
+ output.write(template)
22
+ end
19
23
  end
20
24
  end
21
25
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csv_plus_plus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick Carroll
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-16 00:00:00.000000000 Z
11
+ date: 2023-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: google-apis-drive_v3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: google-apis-sheets_v4
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -100,19 +114,23 @@ description: "A programming language built on top of CSV. You can define functi
100
114
  email: patrick@patrickomatic.com
101
115
  executables:
102
116
  - csv++
117
+ - csvpp
103
118
  extensions: []
104
119
  extra_rdoc_files: []
105
120
  files:
106
121
  - CHANGELOG.md
107
122
  - README.md
108
123
  - bin/csv++
124
+ - bin/csvpp
109
125
  - lib/csv_plus_plus.rb
110
126
  - lib/csv_plus_plus/cell.rb
127
+ - lib/csv_plus_plus/cli.rb
111
128
  - lib/csv_plus_plus/cli_flag.rb
112
129
  - lib/csv_plus_plus/code_section.rb
113
130
  - lib/csv_plus_plus/color.rb
114
131
  - lib/csv_plus_plus/error.rb
115
132
  - lib/csv_plus_plus/expand.rb
133
+ - lib/csv_plus_plus/google_api_client.rb
116
134
  - lib/csv_plus_plus/google_options.rb
117
135
  - lib/csv_plus_plus/graph.rb
118
136
  - lib/csv_plus_plus/language/cell_value.tab.rb
@@ -145,6 +163,7 @@ files:
145
163
  - lib/csv_plus_plus/writer/base_writer.rb
146
164
  - lib/csv_plus_plus/writer/csv.rb
147
165
  - lib/csv_plus_plus/writer/excel.rb
166
+ - lib/csv_plus_plus/writer/file_backer_upper.rb
148
167
  - lib/csv_plus_plus/writer/google_sheet_builder.rb
149
168
  - lib/csv_plus_plus/writer/google_sheet_modifier.rb
150
169
  - lib/csv_plus_plus/writer/google_sheets.rb
@@ -155,13 +174,13 @@ homepage: https://github.com/patrickomatic/csv-plus-plus
155
174
  licenses:
156
175
  - MIT
157
176
  metadata:
158
- rubygems_mfa_required: 'true'
159
177
  bug_tracker_uri: https://github.com/patrickomatic/csv-plus-plus/issues
160
178
  documentation_uri: https://www.rubydoc.info/gems/csv_plus_plus/
161
- github_repo: git://github.com/patrickomatic/csv_plus_plus
162
- homepage_uri: https://github.com/patrickomatic/csv_plus_plus
163
- source_code_uri: https://github.com/patrickomatic/csv_plus_plus
164
- changelog_uri: https://github.com/patrickomatic/csv_plus_plus/blob/main/CHANGELOG.md
179
+ github_repo: git://github.com/patrickomatic/csv-plus-plus
180
+ homepage_uri: https://github.com/patrickomatic/csv-plus-plus
181
+ source_code_uri: https://github.com/patrickomatic/csv-plus-plus
182
+ changelog_uri: https://github.com/patrickomatic/csv-plus-plus/blob/main/CHANGELOG.md
183
+ rubygems_mfa_required: 'true'
165
184
  post_install_message:
166
185
  rdoc_options: []
167
186
  require_paths: