eco-helpers 2.7.16 → 2.7.18

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.
@@ -2,8 +2,7 @@ module Eco
2
2
  class CLI
3
3
  class Config
4
4
  module Help
5
-
6
- def help(*args)
5
+ def help(*_args)
7
6
  raise "this needs to be reimplemented in the child class and return a string"
8
7
  end
9
8
 
@@ -16,11 +15,12 @@ module Eco
16
15
  # Creatas a well aligned line
17
16
  def help_line(key, desc, keys_max_len = key.length, line_len = 100)
18
17
  blanks = keys_max_len + 3 - key.length
19
- blanks = blanks < 0 ? 0 : blanks
18
+ blanks = [blanks, 0].max
20
19
  top_line = " #{key}#{" "*blanks} "
21
20
  indent = top_line.length
22
21
  first = true
23
- each_slice_words(desc, line_len - indent).each_with_object([]) do |line, lines|
22
+
23
+ each_slice_words(desc, line_len - indent).each_with_object([]) do |line, lines| # rubocop:disable Style/RedundantEach
24
24
  lines << (first ? "#{top_line}#{line}" : "#{" " * indent}#{line}")
25
25
  first = false
26
26
  end.join("\n")
@@ -33,14 +33,16 @@ module Eco
33
33
  liner << part
34
34
  else
35
35
  yield(liner) if block_given?
36
- out << liner
36
+
37
+ out << liner
37
38
  liner = part.strip
38
39
  end
39
40
  end.tap do |out|
40
- if out.empty? || !liner.empty?
41
- yield(liner) if block_given?
42
- out << liner if liner
43
- end
41
+ next unless out.empty? || !liner.empty?
42
+
43
+ yield(liner) if block_given?
44
+
45
+ out << liner if liner
44
46
  end
45
47
  end
46
48
  end
@@ -2,14 +2,13 @@ module Eco
2
2
  class CLI
3
3
  class Config
4
4
  class Input
5
-
6
5
  attr_reader :core_config
7
6
  attr_reader :default_option
8
7
 
9
8
  def initialize(core_config:, default_option: nil)
10
9
  @core_config = core_config
11
10
  @default_option = default_option
12
- @callbacks = {}
11
+ @callbacks = {}
13
12
  end
14
13
 
15
14
  def default_option?
@@ -20,16 +19,17 @@ module Eco
20
19
  option ||= default_option
21
20
  raise "Missing option to identify the input (no default defined)" unless !!option
22
21
  raise "Missing block to define the input obtention process" unless block
22
+
23
23
  @callbacks[option] = block
24
24
  end
25
25
 
26
26
  def get(io:, option: nil)
27
- unless io && io.is_a?(Eco::API::UseCases::BaseIO)
28
- raise "You need to provide Eco::API::UseCases::BaseIO object. Given: #{io.class}"
29
- end
27
+ msg = "You need to provide Eco::API::UseCases::BaseIO object. Given: #{io.class}"
28
+ raise ArgumentError, msg unless io.is_a?(Eco::API::UseCases::BaseIO)
30
29
 
31
30
  option ||= default_option
32
- raise "Missing option to identify the input (no default defined)" unless !!option
31
+ raise "Missing option to identify the input (no default defined)" unless option
32
+
33
33
  callback = @callbacks[option] || @callbacks[default_option]
34
34
  callback.call(io.session, option, io.options)
35
35
  end
@@ -3,10 +3,10 @@ module Eco
3
3
  class Config
4
4
  class OptionsSet
5
5
  include Eco::CLI::Config::Help
6
+
6
7
  attr_reader :core_config
7
8
 
8
- class OptConfig < Struct.new(:name, :namespace, :description, :callback)
9
- end
9
+ OptConfig = Struct.new(:name, :namespace, :description, :callback)
10
10
 
11
11
  def initialize(core_config:)
12
12
  @core_config = core_config
@@ -15,19 +15,21 @@ module Eco
15
15
 
16
16
  # @return [String] summary of the options.
17
17
  def help(refine: nil)
18
- indent = 2
19
- spaces = any_non_general_space_active? ? active_namespaces : namespaces
18
+ indent = 2
19
+ spaces = any_non_general_space_active? ? active_namespaces : namespaces
20
20
  refinement = refine.is_a?(String)? " (containing: '#{refine}')" : ""
21
- ["The following are the available options#{refinement}:"].yield_self do |lines|
21
+
22
+ ["The following are the available options#{refinement}:"].then do |lines|
22
23
  max_len = keys_max_len(options_args(spaces)) + indent
23
24
  spaces.each do |namespace|
24
25
  is_general = (namespace == :general)
25
26
  str_indent = is_general ? "" : " " * indent
26
27
  lines << help_line(namespace, "", max_len) unless is_general
27
- options_set(namespace).select do |arg, option|
28
+
29
+ options_set(namespace).select do |_arg, option| # rubocop:disable Style/HashEachMethods
28
30
  !refine.is_a?(String) || option.name.include?(refine)
29
- end.each do |arg, option|
30
- lines << help_line(" " * indent + "#{option.name}", option.description, max_len)
31
+ end.each do |_arg, option|
32
+ lines << help_line("#{str_indent}#{option.name}", option.description, max_len)
31
33
  end
32
34
  end
33
35
  lines
@@ -41,6 +43,19 @@ module Eco
41
43
  end.uniq
42
44
  end
43
45
 
46
+ # Options that are known for active namespaces (CLI-present)
47
+ def available(keys: false)
48
+ sets.select do |namespace, _opts_set|
49
+ active_namespace?(namespace)
50
+ end.each_value.with_object([]) do |opts_set, options|
51
+ options.concat(opts_set.values)
52
+ end.then do |options|
53
+ next options unless keys
54
+
55
+ options.map(&:name)
56
+ end
57
+ end
58
+
44
59
  # @param option [String, Array<String>] the command line option(s).
45
60
  # @param namespace [String] preceding command(s) argument that enables this option.
46
61
  # @param desc [String] description of the option.
@@ -51,17 +66,18 @@ module Eco
51
66
  unless opts.empty?
52
67
  callback = block
53
68
  opts.each do |opt|
54
- puts "Overriding CLI option '#{option}' in '#{namespace}' CLI case / namespace" if option_exists?(opt, namespace)
69
+ msg = "Overriding CLI option '#{option}' in '#{namespace}' CLI case / namespace"
70
+ puts msg if option_exists?(opt, namespace)
55
71
  options_set(namespace)[opt] = OptConfig.new(opt, namespace, desc, callback)
56
72
  end
57
73
  end
74
+
58
75
  self
59
76
  end
60
77
 
61
78
  def process(io:)
62
- unless io && io.is_a?(Eco::API::UseCases::BaseIO)
63
- raise "You need to provide Eco::API::UseCases::BaseIO object. Given: #{io.class}"
64
- end
79
+ msg = "You need to provide Eco::API::UseCases::BaseIO object. Given: #{io.class}"
80
+ raise ArgumentError, msg unless io.is_a?(Eco::API::UseCases::BaseIO)
65
81
 
66
82
  active_options.each do |option|
67
83
  option.callback.call(io.options, io.session)
@@ -70,8 +86,9 @@ module Eco
70
86
  io.options
71
87
  end
72
88
 
89
+ # Options that have been invoked via CLI
73
90
  def active_options
74
- @active_options ||= sets.select do |namespace, opts_set|
91
+ @active_options ||= sets.select do |namespace, _opts_set|
75
92
  active_namespace?(namespace)
76
93
  end.each_with_object([]) do |(namespace, opts_set), options|
77
94
  opts_set.each do |arg, option|
@@ -81,19 +98,20 @@ module Eco
81
98
  end
82
99
 
83
100
  def all_options
84
- sets.each_with_object([]) do |(namespace, opts_set), options|
101
+ sets.each_with_object([]) do |(_namespace, opts_set), options|
85
102
  options << opts_set.values
86
103
  end
87
104
  end
88
105
 
89
106
  def namespaces
90
107
  sets.keys.sort_by do |key|
91
- key == :general
108
+ next 1 if key == :general
109
+ 0
92
110
  end
93
111
  end
94
112
 
95
113
  def any_non_general_space_active?
96
- (active_namespaces - [:general]).length > 0
114
+ (active_namespaces - [:general]).length.positive?
97
115
  end
98
116
 
99
117
  def active_namespaces
@@ -104,7 +122,6 @@ module Eco
104
122
  end
105
123
  end
106
124
 
107
-
108
125
  private
109
126
 
110
127
  def active_namespace?(namespace)
@@ -132,10 +149,6 @@ module Eco
132
149
  }
133
150
  end
134
151
 
135
- def namespaces
136
- @sets.keys
137
- end
138
-
139
152
  def options_set(namespace = :general)
140
153
  @sets[namespace] ||= {}
141
154
  end
@@ -39,6 +39,15 @@ module Eco
39
39
  end.join("\n")
40
40
  end
41
41
 
42
+ # The linked cases
43
+ def available(keys: false)
44
+ @linked_cases.values.then do |cases|
45
+ next cases unless keys
46
+
47
+ cases.map(&:option)
48
+ end
49
+ end
50
+
42
51
  # Integrates a usecase to the command line.
43
52
  # @param option_case [String] the command line option to invoke the usecase.
44
53
  # @param type [Symbol] the type of usecase.
@@ -46,10 +55,12 @@ module Eco
46
55
  # @param case_name [String, nil] the name of the usecase as defined.
47
56
  def add(option_case, type, desc = nil, case_name: nil, &callback)
48
57
  Eco::API::UseCases::UseCase.validate_type(type)
58
+
49
59
  unless block_given?
50
60
  raise "You must specify a valid 'case_name' when no block is provided" unless case_name
51
61
  raise "'case_name' expected to be a String. Given: #{case_name.class}" unless case_name.is_a?(String)
52
62
  end
63
+
53
64
  puts "Overriding CLI case '#{option_case}'" if @linked_cases.key?(option_case)
54
65
  @linked_cases[option_case] = CaseConfig.new(self, option_case, type, desc, case_name, callback)
55
66
  end
@@ -60,6 +71,7 @@ module Eco
60
71
  io.session.usecases.each do |usecase|
61
72
  next unless usecase.respond_to?(:classed_definition)
62
73
  next unless (original_case = usecase.classed_definition)
74
+
63
75
  original_case.cli_apply!
64
76
  end
65
77
  end
@@ -84,9 +96,12 @@ module Eco
84
96
 
85
97
  def process(io:)
86
98
  validate_io!(io)
99
+
87
100
  processed = false
101
+
88
102
  active(io: io).each do |usecase, data|
89
103
  raise "Something went wrong when scoping active cases" unless data
104
+
90
105
  processed = true
91
106
  io = case_io(io: io, usecase: usecase)
92
107
  # some usecases have a callback to collect the parameters
@@ -101,6 +116,7 @@ module Eco
101
116
  # Gets a `UseCaseIO`
102
117
  def case_io(io:, usecase:)
103
118
  validate_io!(io)
119
+
104
120
  case io
105
121
  when Eco::API::UseCases::UseCaseIO
106
122
  io.chain(usecase: usecase)
@@ -122,12 +138,12 @@ module Eco
122
138
  params = io.params(keyed: true).merge(type: data.type)
123
139
  io = io.new(**params, validate: false)
124
140
  callback.call(*io.params).tap do |use|
125
- unless use.is_a?(Eco::API::UseCases::UseCase)
126
- msg = "When adding a usecase, without specifying 'case_name:', "
127
- msg += "the block that integrates usecase for cli option '#{data.option}'"
128
- msg += " must return an Eco::API::UseCases::UseCase object. It returns #{use.class}"
129
- raise msg
130
- end
141
+ next if use.is_a?(Eco::API::UseCases::UseCase)
142
+
143
+ msg = "When adding a usecase, without specifying 'case_name:', "
144
+ msg << "the block that integrates usecase for cli option '#{data.option}'"
145
+ msg << "must return an Eco::API::UseCases::UseCase object. It returns #{use.class}"
146
+ raise msg
131
147
  end
132
148
  end
133
149
  end
@@ -1,7 +1,6 @@
1
1
  module Eco
2
2
  class CLI
3
3
  class Config
4
-
5
4
  attr_reader :cli
6
5
 
7
6
  def initialize(cli:)
@@ -16,6 +15,16 @@ module Eco
16
15
  cli.args
17
16
  end
18
17
 
18
+ # All the available known option args that can be used in the CLI
19
+ def available_option_args
20
+ [
21
+ usecases.available(keys: true),
22
+ options_set.available(keys: true),
23
+ people_filters.available(keys: true),
24
+ input_filters.available(keys: true)
25
+ ].flatten.uniq
26
+ end
27
+
19
28
  def options_set
20
29
  @opions_set ||= Eco::CLI::Config::OptionsSet.new(core_config: self)
21
30
  @opions_set.tap do |opts_set|
@@ -25,12 +34,10 @@ module Eco
25
34
 
26
35
  def input(default_option: nil, &block)
27
36
  @input ||= Eco::CLI::Config::Input.new(core_config: self, default_option: default_option)
28
- if block_given?
29
- @input.define(&block)
30
- self
31
- else
32
- @input
33
- end
37
+ return @input unless block_given?
38
+
39
+ @input.define(&block)
40
+ self
34
41
  end
35
42
 
36
43
  def people(io: nil, &block)
@@ -38,10 +45,11 @@ module Eco
38
45
  @people_load = block
39
46
  self
40
47
  else
41
- raise "There is no definition on how to load people" unless instance_variable_defined?(:@people_load) && @people_load
42
- unless io && io.is_a?(Eco::API::UseCases::BaseIO)
43
- raise "You need to provide Eco::API::UseCases::BaseIO object. Given: #{io.class}"
44
- end
48
+ msg = "There is no definition on how to load people"
49
+ raise msg unless instance_variable_defined?(:@people_load) && @people_load
50
+
51
+ msg = "You need to provide Eco::API::UseCases::BaseIO object. Given: #{io.class}"
52
+ raise msg unless io.is_a?(Eco::API::UseCases::BaseIO)
45
53
 
46
54
  io = io.new(type: :import, input: io.input || [])
47
55
  @people_load.call(*io.params)
@@ -7,7 +7,7 @@ module Eco
7
7
  @argv || ARGV
8
8
  end
9
9
 
10
- def is_modifier?(value)
10
+ def is_modifier?(value) # rubocop:disable Naming/PredicateName
11
11
  Argument.is_modifier?(value)
12
12
  end
13
13
 
@@ -21,22 +21,34 @@ module Eco
21
21
  arguments.add(key, with_param: with_param)
22
22
  end
23
23
 
24
-
25
24
  # Validation to stop the `script` if among `argv` there's any **unknown** argument.
26
- def stop_on_unknown!(exclude: [], only_options: false)
25
+ def stop_on_unknown!(exclude: [], only_options: false, all_available: nil)
27
26
  # validate only those that are options
28
- unknown = arguments.unknown(exclude: exclude)
29
- if only_options
30
- unknown = unknown..select {|arg| is_modifier?(arg)}
27
+ suggestions = {}
28
+ args = {
29
+ exclude: exclude,
30
+ all_available: all_available
31
+ }
32
+ unknown = arguments.unknown(**args) do |key, correct|
33
+ suggestions[key] = correct unless correct.empty?
31
34
  end
35
+ unknown = unknown.select {|arg| is_modifier?(arg)} if only_options
32
36
 
33
- unless unknown.empty?
34
- msg = "There are unknown options in your command line arguments:\n"
35
- msg += "#{unknown}\n"
36
- msg += "Please, remember that use case specific options should come after the use case in the command line.\n"
37
- msg += "Use 'ruby main.rb -org [-usecase] --help -options' for more information"
38
- raise msg
39
- end
37
+ return if unknown.empty?
38
+
39
+ suggestions_str = suggestions.slice(*unknown).map do |key, correct|
40
+ str = "Unknown option '#{key}'."
41
+ str_corr = correct.map {|key| "'#{key}'"}
42
+ str << " Did you mean: #{str_corr.join(', ')}" unless correct.empty?
43
+ str
44
+ end.join("\n * ")
45
+
46
+ msg = "\nThere are UNKNOWN OPTIONS in your command line arguments !!"
47
+ msg << "\n * #{suggestions_str}\n"
48
+ msg << "\nUse 'ruby main.rb -org [-usecase] --help -options' for more information"
49
+ msg << "\n - Please, remember that use case specific options "
50
+ msg << "should come after the use case in the command line.\n"
51
+ raise msg
40
52
  end
41
53
 
42
54
  # @return [Boolean] if `key` is in the command line.
@@ -46,28 +58,31 @@ module Eco
46
58
 
47
59
  # @return [Integer, nil] the position of `key` in the command line.
48
60
  def get_arg_index(key)
49
- return nil if !arg?(key)
61
+ return unless arg?(key)
62
+
50
63
  argv.index(key)
51
64
  end
52
65
 
53
66
  # @return [Boolean] if `key1` precedes `key2` in the command line.
54
- def arg_order?(key1, key2)
55
- return false unless (k1 = get_arg_index(key1)) && k2 = get_arg_index(key2)
56
- k1 < k2
67
+ def arg_order?(key_1, key_2)
68
+ k_1 = get_arg_index(key_1)
69
+ k_2 = get_arg_index(key_2)
70
+ return false unless k_1 && k_2
71
+
72
+ k_1 < k_2
57
73
  end
58
74
 
59
75
  # @return [String, Boolean] the argument value if `with_param` or a `Boolean` if not.
60
76
  def get_arg(key, with_param: false, valid: true)
61
77
  # track what a known option looks like
62
78
  known_argument(key, with_param: with_param)
63
- return nil unless index = get_arg_index(key)
64
- value = true
65
- if with_param
66
- value = argv[index + 1]
67
- #puts "modifier argument: #{value}"
68
- value = nil if valid && is_modifier?(value)
69
- end
70
- return value
79
+ return nil unless (index = get_arg_index(key))
80
+ return true unless with_param
81
+
82
+ value = argv[index + 1]
83
+ #puts "modifier argument: #{value}"
84
+ value = nil if valid && is_modifier?(value)
85
+ value
71
86
  end
72
87
 
73
88
  # @return [String] the filename.
@@ -13,6 +13,7 @@ module Eco
13
13
 
14
14
  def each(&block)
15
15
  return to_enum(:each) unless block
16
+
16
17
  @known.values.each(&block)
17
18
  end
18
19
 
@@ -22,7 +23,8 @@ module Eco
22
23
 
23
24
  def <<(arg)
24
25
  raise "Expected Argument. Given #{arg.class}" unless arg.is_a?(Argument)
25
- if karg = @known[arg.key]
26
+
27
+ if (karg = @known[arg.key])
26
28
  #puts "Found already existent option #{arg.key} (with_param: arg.with_param?)"
27
29
  karg.with_param! if arg.with_param?
28
30
  else
@@ -40,14 +42,33 @@ module Eco
40
42
  @known.keys
41
43
  end
42
44
 
43
- def unknown(exclude: [])
45
+ def unknown(exclude: [], all_available: nil)
44
46
  reduce(args.dup - exclude) do |not_known, arg|
45
47
  arg.args_slice(*not_known)
48
+ end.compact.tap do |list|
49
+ list.each do |key|
50
+ next unless block_given?
51
+
52
+ yield(key, unknown_suggestions(key, all_available: all_available))
53
+ end
46
54
  end
47
55
  end
48
56
 
57
+ def unknown_suggestions(str, all_available: nil)
58
+ return [] if str.nil?
59
+
60
+ str = str.to_s.strip
61
+ return [] if str.empty?
62
+
63
+ all_available ||= @known.keys
64
+ spell_checker = DidYouMean::SpellChecker.new(
65
+ dictionary: all_available
66
+ )
67
+ spell_checker.correct(str)
68
+ end
69
+
49
70
  def any_unknown?(exclude: [])
50
- unknown(exclude: exclude).length > 0
71
+ unknown(exclude: exclude).length.positive?
51
72
  end
52
73
 
53
74
  private
data/lib/eco/cli.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Eco
2
2
  class CLI
3
-
4
3
  def initialize
5
4
  @config = nil
6
5
  end
@@ -74,8 +74,9 @@ ASSETS.cli do |cli| # rubocop:disable Metrics/BlockLength
74
74
  end
75
75
  end
76
76
 
77
- wf.before(:launch_jobs) do
78
- SCR.stop_on_unknown!
77
+ wf.before(:launch_jobs) do |_wf_jobs, io|
78
+ available_args = cli.config.available_option_args
79
+ SCR.stop_on_unknown!(all_available: available_args)
79
80
  end
80
81
 
81
82
  wf.on(:launch_jobs) do
data/lib/eco/csv/split.rb CHANGED
@@ -5,10 +5,13 @@ module Eco
5
5
 
6
6
  attr_reader :filename
7
7
 
8
- def initialize(filename, max_rows:, **kargs)
9
- raise ArgumentError, "File '#{filename}' does not exist" unless ::File.exist?(filename)
8
+ def initialize(filename, max_rows:, start_at: nil, **kargs)
9
+ msg = "File '#{filename}' does not exist"
10
+ raise ArgumentError, msg unless ::File.exist?(filename)
11
+
10
12
  @filename = filename
11
13
  @max_rows = max_rows
14
+ @start_at = start_at
12
15
  @params = kargs
13
16
  init
14
17
  end
@@ -20,7 +23,7 @@ module Eco
20
23
  # - If `nil` it will create its own filename convention
21
24
  # @return [Array<String>] names of the generated files
22
25
  def call(&block)
23
- stream.for_each do |row, ridx|
26
+ stream.for_each(start_at_idx: start_at) do |row, ridx|
24
27
  copy_row(row, ridx, &block)
25
28
  end
26
29
  out_files
@@ -32,7 +35,7 @@ module Eco
32
35
  private
33
36
 
34
37
  attr_reader :params
35
- attr_reader :idx, :max_rows
38
+ attr_reader :idx, :max_rows, :start_at
36
39
  attr_reader :headers, :row_idx
37
40
 
38
41
  attr_accessor :exception
@@ -40,19 +43,29 @@ module Eco
40
43
  def copy_row(row, ridx, &block)
41
44
  @headers ||= row.headers
42
45
  @row_idx = ridx
43
- current_csv(ridx, &block) << row.fields
46
+
47
+ current_csv(ridx) do |csv, fidx, file_out|
48
+ included = true
49
+ included &&= !block || yield(row, ridx, fidx, file_out)
50
+ next unless included
51
+
52
+ csv << row.fields
53
+ end
44
54
  end
45
55
 
46
56
  def current_csv(ridx)
47
57
  if split?(ridx) || @csv.nil?
48
58
  puts "Split at row #{row_idx}"
49
59
  @csv&.close
50
- out_filename = generate_name(nidx = next_idx)
51
- out_filename = yield(nidx, out_filename) if block_given?
52
- @csv = ::CSV.open(out_filename, "w")
53
- @csv << headers
54
- out_files << out_filename
60
+
61
+ out_filename = generate_name(next_idx)
62
+ @csv = ::CSV.open(out_filename, "w")
63
+ @csv << headers
64
+ out_files << out_filename
55
65
  end
66
+
67
+ yield(@csv, idx, out_files.last) if block_given?
68
+
56
69
  @csv
57
70
  end
58
71
 
@@ -37,6 +37,7 @@ module Eco
37
37
  end
38
38
 
39
39
  def move_to_idx(start_at_idx)
40
+ start_at_idx ||= 0
40
41
  next_idx while (idx < start_at_idx) && (self.row = csv.shift)
41
42
  end
42
43
 
data/lib/eco/csv.rb CHANGED
@@ -18,16 +18,38 @@ module Eco
18
18
  parse(get_file_content(file, **params), **kargs)
19
19
  end
20
20
 
21
- # @yield [idx, file] a block to spot the filename
22
- # @yieldparam idx [Integer] the number of the file
21
+ # Splits the csv `filename` into `max_rows`
22
+ # @yield [row, ridx, fidx, file]
23
+ # @yieldparam row [Integer] the row
24
+ # @yieldparam ridx [Integer] the index of the row in the source file
25
+ # @yieldparam fidx [Integer] the number of the file
23
26
  # @yieldparam file [String] the default name of the file
24
- # @yieldreturn [String] the filename of the file `idx`.
25
- # - If `nil` it will create its own filename convention
27
+ # @yieldreturn [Bollean] whether the row should be included
26
28
  # @param filename [String] the orignal file
27
29
  # @param max_rows [Integer] number of rows per file
30
+ # @param start_at [Integer] row that sets the starting point.
31
+ # Leave empty for the full set of rows.
28
32
  # @see Eco::CSV::Split#call
29
- def split(filename, max_rows:, **kargs, &block)
30
- Eco::CSV::Split.new(filename, max_rows: max_rows, **kargs).call(&block)
33
+ def split(filename, max_rows:, start_at: nil, **kargs, &block)
34
+ Eco::CSV::Split.new(
35
+ filename,
36
+ max_rows: max_rows,
37
+ start_at: start_at,
38
+ **kargs
39
+ ).call(&block)
40
+ end
41
+
42
+ # @note it excludes headers by default
43
+ # @return [Integer] the number of rows of the file
44
+ def count(filename, start_at: nil, **kargs)
45
+ count = 0
46
+ streamer = Eco::CSV::Stream.new(filename, **kargs)
47
+ streamer.for_each(start_at_idx: start_at) do |row|
48
+ included = true
49
+ included = yield(row) if block_given?
50
+ count += 1 if included
51
+ end
52
+ count
31
53
  end
32
54
  end
33
55
  end
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = '2.7.16'.freeze
2
+ VERSION = '2.7.18'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eco-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.16
4
+ version: 2.7.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura