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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -3
- data/lib/eco/api/common/loaders/config/workflow/mailer.rb +10 -1
- data/lib/eco/api/microcases/people_cache.rb +3 -4
- data/lib/eco/api/microcases/people_load.rb +11 -8
- data/lib/eco/api/microcases/people_refresh.rb +8 -7
- data/lib/eco/api/microcases/people_search.rb +28 -22
- data/lib/eco/api/usecases/cli/dsl.rb +8 -6
- data/lib/eco/api/usecases/cli/option.rb +1 -0
- data/lib/eco/api/usecases/default/utils/cli/split_csv_cli.rb +5 -0
- data/lib/eco/api/usecases/default/utils/split_csv_case.rb +24 -4
- data/lib/eco/api/usecases/default_cases/to_csv_case.rb +36 -12
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff.rb +13 -1
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/parser.rb +5 -5
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter.rb +3 -5
- data/lib/eco/cli/config/filters.rb +13 -3
- data/lib/eco/cli/config/help.rb +11 -9
- data/lib/eco/cli/config/input.rb +6 -6
- data/lib/eco/cli/config/options_set.rb +34 -21
- data/lib/eco/cli/config/use_cases.rb +22 -6
- data/lib/eco/cli/config.rb +19 -11
- data/lib/eco/cli/scripting/args_helpers.rb +40 -25
- data/lib/eco/cli/scripting/arguments.rb +24 -3
- data/lib/eco/cli.rb +0 -1
- data/lib/eco/cli_default/workflow.rb +3 -2
- data/lib/eco/csv/split.rb +23 -10
- data/lib/eco/csv/stream.rb +1 -0
- data/lib/eco/csv.rb +28 -6
- data/lib/eco/version.rb +1 -1
- metadata +1 -1
data/lib/eco/cli/config/help.rb
CHANGED
@@ -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
|
18
|
+
blanks = [blanks, 0].max
|
20
19
|
top_line = " #{key}#{" "*blanks} "
|
21
20
|
indent = top_line.length
|
22
21
|
first = true
|
23
|
-
|
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
|
-
|
36
|
+
|
37
|
+
out << liner
|
37
38
|
liner = part.strip
|
38
39
|
end
|
39
40
|
end.tap do |out|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
data/lib/eco/cli/config/input.rb
CHANGED
@@ -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
|
-
|
28
|
-
|
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
|
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
|
-
|
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
|
19
|
-
spaces
|
18
|
+
indent = 2
|
19
|
+
spaces = any_non_general_space_active? ? active_namespaces : namespaces
|
20
20
|
refinement = refine.is_a?(String)? " (containing: '#{refine}')" : ""
|
21
|
-
|
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
|
-
|
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 |
|
30
|
-
lines << help_line("
|
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
|
-
|
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
|
-
|
63
|
-
|
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,
|
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 |(
|
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
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
data/lib/eco/cli/config.rb
CHANGED
@@ -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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
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?(
|
55
|
-
|
56
|
-
|
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
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
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
|
71
|
+
unknown(exclude: exclude).length.positive?
|
51
72
|
end
|
52
73
|
|
53
74
|
private
|
data/lib/eco/cli.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
51
|
-
out_filename =
|
52
|
-
@csv
|
53
|
-
@csv
|
54
|
-
out_files
|
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
|
|
data/lib/eco/csv/stream.rb
CHANGED
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
|
-
#
|
22
|
-
# @
|
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 [
|
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(
|
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