flex-cartesian 1.2.2 → 1.3.1

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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +12 -2
  4. data/lib/flex-cartesian.rb +43 -10
  5. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a2ca7796b432b25c13982324959267a48475d5e9bce840b36309f976e05aa8f
4
- data.tar.gz: c43b4a80cda5177c29cd7e07c186d6075fa2597ed3fe3e4e886e49b94b76ef49
3
+ metadata.gz: 879d7780851f01bc807133456d82734f8f2d064e8d258b566d310557f98dd705
4
+ data.tar.gz: df91fa942cf22252273cbc0b65b145a005c7071b415a99f3b485fecf3b813e64
5
5
  SHA512:
6
- metadata.gz: 8271368f575fdd9dc460d6acb7d37678faf8071293738c9cf421ad7fa3dbc0bcf197590d79e57216cc20ee4b028ffa0b58f84b160dddb900b71d778ba93ef8e8
7
- data.tar.gz: 4e55180b78619c9ad100c0b6e7db1b19cc7c74871936939340d53af7b6e01eba82bd2bd2e739e0e33c3ef334cfb66f75284aeae1ef2ca1dcebbe00f60eb5843a
6
+ metadata.gz: 46a20d5b4ff80f8980170a160786164cfab11557d592f089b04a1fb9a24b51203db5e41c9b6bccc48968244d5190a08e8ed5befce453f71dff58583c93ffa8e5
7
+ data.tar.gz: 17e76c180e6c3c38cb89e3d73771ad9271bff04fcf740ba3910f472f262e6d8630f9d2e36e6d52eadd740f7a13552642c83ec39504cdc6f7e89b99f9a844beb0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.3.1 - 2025-09-03
4
+ ## Fixed
5
+ - CSV format expects separator to be one of ";" or "," otherwise enforces ";"
6
+
7
+ ## 1.3.0 - 2025-08-19
8
+ ### Added
9
+ - .func accepts flag order:
10
+
3
11
  ## 1.2.2 - 2025-07-28
4
12
  ### Added
5
13
  - .dimensions functionality extended to more granular formatting
data/README.md CHANGED
@@ -179,7 +179,16 @@ puts "\Add and then remove function 'test'"
179
179
  s.func(:add, :test) { |v| v.dim3.to_i }
180
180
  s.func(:del, :test)
181
181
 
182
+ puts "\nThis function will calculate first, always"
183
+ s.func(:add, :test_first, order: :first) { puts "HERE" }
182
184
 
185
+ puts "\nThis function will calculate last, always"
186
+ s.func(:add, :test_last, order: :last) { puts "HERE" }
187
+
188
+ puts "\nNew functions respect first and last ones"
189
+ s.func(:add, :test_more) { puts "HERE" }
190
+
191
+ puts "\nFirst and last functions are handy for pre- and post-processing for each combination"
183
192
 
184
193
  # CONDITIONS ON CARTESIAN SPACE
185
194
 
@@ -377,7 +386,7 @@ s.cartesian { |v| puts "#{v.dim1} - #{v.dim2}" }
377
386
 
378
387
  ### Handling Functions
379
388
  ```ruby
380
- func(command = :print, name = nil, hide: false, progress: false, title: "calculating functions", &block)
389
+ func(command = :print, name = nil, hide: false, progress: false, title: "calculating functions", order: nil, &block)
381
390
  ```
382
391
  - `command`: symbol, one of the following
383
392
  - `:add` to add function as a virtual dimension to Cartesian space
@@ -388,6 +397,7 @@ func(command = :print, name = nil, hide: false, progress: false, title: "calcula
388
397
  - `hide`: flag that hides or shows the function in .output; it is useful to hide intermediate calculations
389
398
  - `progress`: show progress bar during `:run`, useful for large Cartesian space
390
399
  - `title`: title of the progress bar
400
+ - `order`: can be `:first` or `:last` to make the function calculate before or after all other functions
391
401
  - `block`: a function that receives each vector and returns a computed value
392
402
 
393
403
  Functions show up in `.output` like additional (virtual) dimensions.
@@ -442,7 +452,7 @@ Displays a progress bar using `ruby-progressbar`.
442
452
  ```ruby
443
453
  output(separator: " | ", colorize: false, align: true, format: :plain, limit: nil, file: nil)
444
454
  ```
445
- - `separator`: how to visually separate columns in the output
455
+ - `separator`: how to visually separate columns in the output. For :csv, it defaults to ";" unless it's one of ";" or ","
446
456
  - `colorize`: whether to colorize output or not
447
457
  - `align`: whether to align output by column or not
448
458
  - `format`: one of `:plain`, `:markdown`, or `:csv`
@@ -34,6 +34,7 @@ class FlexCartesian
34
34
  @dimensions = dimensions
35
35
  @conditions = []
36
36
  @derived = {}
37
+ @order = { first: nil, last: nil }
37
38
  @function_results = {} # key: Struct instance.object_id => { fname => value }
38
39
  @function_hidden = Set.new
39
40
  import(path, format: format) if path
@@ -71,11 +72,11 @@ class FlexCartesian
71
72
  end
72
73
  end
73
74
 
74
- def func(command = :print, name = nil, hide: false, progress: false, title: "calculating functions", &block)
75
+ def func(command = :print, name = nil, hide: false, progress: false, title: "calculating functions", order: nil, &block)
75
76
  case command
76
77
  when :add
77
78
  raise ArgumentError, "Function name and block required for :add" unless name && block_given?
78
- add_function(name, &block)
79
+ add_function(name, order: order, &block)
79
80
  @function_hidden.delete(name.to_sym)
80
81
  @function_hidden << name.to_sym if hide
81
82
 
@@ -89,10 +90,17 @@ def func(command = :print, name = nil, hide: false, progress: false, title: "cal
89
90
  else
90
91
  @derived.each do |fname, fblock|
91
92
  source = fblock.source rescue '(source unavailable)'
92
-
93
93
  body = source.sub(/^.*?\s(?=(\{|\bdo\b))/, '').strip
94
-
95
- puts " #{fname.inspect.ljust(12)}| #{body}#{@function_hidden.include?(fname) ? ' [HIDDEN]' : ''}"
94
+ order = ""
95
+ if @order.value?(fname.to_sym)
96
+ case @order.key(fname.to_sym)
97
+ when :first
98
+ order = " [FIRST]"
99
+ when :last
100
+ order = " [LAST]"
101
+ end
102
+ end
103
+ puts " #{fname.inspect.ljust(12)}| #{body}#{@function_hidden.include?(fname) ? ' [HIDDEN]' : ''}#{order}"
96
104
  end
97
105
  end
98
106
 
@@ -124,18 +132,38 @@ def func(command = :print, name = nil, hide: false, progress: false, title: "cal
124
132
  end
125
133
  end
126
134
 
127
- def add_function(name, &block)
135
+ def add_function(name, order: nil , &block)
128
136
  raise ArgumentError, "Block required" unless block_given?
129
137
  if reserved_function_names.include?(name.to_sym)
130
138
  raise ArgumentError, "Function name '#{name}' has been already added"
131
139
  elsif reserved_struct_names.include?(name.to_sym)
132
140
  raise ArgumentError, "Name '#{name}' has been reserved for internal method, you can't use it for a function"
133
141
  end
134
- @derived[name.to_sym] = block
142
+ if order == :last
143
+ @derived[name.to_sym] = block # add to the tail of the hash
144
+ @order[:last] = name.to_sym
145
+ elsif order == :first
146
+ @derived = { name.to_sym => block }.merge(@derived) # add to the head of the hash
147
+ @order[:first] = name.to_sym
148
+ elsif order == nil
149
+ if @order[:last] != nil
150
+ last_name = @order[:last]
151
+ last_body = @derived[last_name]
152
+ @derived.delete(@order[:last]) # remove the tail of the hash
153
+ @derived[name.to_sym] = block # add new function to the tail of the hash
154
+ @derived[last_name] = last_body # restore :last function in the tail of the hash
155
+ else
156
+ @derived[name.to_sym] = block
157
+ end
158
+ else
159
+ raise ArgumentError, "unknown function order '#{order}'"
160
+ end
135
161
  end
136
162
 
137
163
  def remove_function(name)
138
164
  @derived.delete(name.to_sym)
165
+ @order[:last] = nil if @order[:last] == name.to_sym
166
+ @order[:first] = nil if @order[:first] == name.to_sym
139
167
  end
140
168
 
141
169
  def cartesian(dims = nil, lazy: false)
@@ -201,6 +229,11 @@ end
201
229
  end
202
230
 
203
231
  def output(separator: " | ", colorize: false, align: true, format: :plain, limit: nil, file: nil)
232
+ sep = if format == :csv
233
+ [";", ","].include?(separator) ? separator : ";"
234
+ else
235
+ separator
236
+ end
204
237
  rows = if @function_results && !@function_results.empty?
205
238
  @function_results.keys
206
239
  else
@@ -237,9 +270,9 @@ def output(separator: " | ", colorize: false, align: true, format: :plain, limit
237
270
  lines << "| " + headers.map { |h| h.ljust(widths[h] || h.size) }.join(" | ") + " |"
238
271
  lines << "|-" + headers.map { |h| "-" * (widths[h] || h.size) }.join("-|-") + "-|"
239
272
  when :csv
240
- lines << headers.join(",")
273
+ lines << headers.join(sep)
241
274
  else
242
- lines << headers.map { |h| fmt_cell(h, colorize, widths[h]) }.join(separator)
275
+ lines << headers.map { |h| fmt_cell(h, colorize, widths[h]) }.join(sep)
243
276
  end
244
277
 
245
278
  # Rows
@@ -248,7 +281,7 @@ def output(separator: " | ", colorize: false, align: true, format: :plain, limit
248
281
  visible_func_names.map { |fname| @function_results&.dig(row, fname) }
249
282
 
250
283
  line = headers.zip(values).map { |(_, val)| fmt_cell(val, colorize, widths[_]) }
251
- lines << (format == :csv ? line.join(",") : line.join(separator))
284
+ lines << line.join(sep)
252
285
  end
253
286
 
254
287
  # Output to console or file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flex-cartesian
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yury Rassokhin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-28 00:00:00.000000000 Z
11
+ date: 2025-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -115,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
117
  requirements: []
118
- rubygems_version: 3.2.33
118
+ rubygems_version: 3.4.10
119
119
  signing_key:
120
120
  specification_version: 4
121
121
  summary: Flexible and human-friendly Cartesian product enumerator for Ruby