flex-cartesian 0.1.8 → 0.1.9

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 +10 -0
  3. data/README.md +130 -31
  4. data/lib/flex-cartesian.rb +38 -6
  5. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e92633e14160e43566c300b7e747f9f8cf742954652a442073ca44f7e0992ca3
4
- data.tar.gz: c0a3ba79e43094b3c8325f23a9c37c8cf9f29a7fc4fb5bd20b34c514cef3e8d0
3
+ metadata.gz: 0b26211b52fac8e2a26ff5408d422e6ae328aefbd67d0a18ac07ef0404006c05
4
+ data.tar.gz: cf406e24632a26605b5002e91ddfdf63bddaeb0a361d2dbbab76f5514bfdec88
5
5
  SHA512:
6
- metadata.gz: 1bd895985ea81a675c38e9feace76e9d3a6b0dca8502fe9065420695c66a75b8e1b4134b55a1144bf9082fe52a60f4c0812317f113ae486c0e739b6e55266bcd
7
- data.tar.gz: 44edb599dff65eb233ef2bd87623cd0c4cf20ca1d5d9d6cb33dfbe504b8c852a3020374dae019efac8193b552590fd7a684637dac58efc7eb6b6de44117246b0
6
+ metadata.gz: 2cb31e4b65dba494aeac390ad1baee384c5eca90aeb67363cb374db4ba0c1e4b4d4f4dc6acac088642a751e9d7d4ee996b98c99abf49fdc98c615981c5c12663
7
+ data.tar.gz: 2b9c27d532a24430cbd21508d91d02d2f29172d9069eab75a8af5c60a2fb25936ff014de5ffc6c5a7df29e08d07de1b7272aefb6edbc907f60a96ae1e1520236
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.9 - 2025-07-08
4
+ ### Fixed
5
+ - Documentation
6
+
7
+ ### Added
8
+ - Unified methods for import and export
9
+ - JSON and YAML can be imported, not only exported
10
+ - Functions can be removed
11
+ - Minor changes in default values of named parameters
12
+
3
13
  ## 0.1.8 - 2025-07-07
4
14
  ### Fixed
5
15
  - Documentation
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  **Ruby implementation of flexible and human-friendly operations on Cartesian products**
4
4
 
5
+
6
+
5
7
  ## Features
6
8
 
7
9
  ✅ Named dimensions with arbitrary keys
@@ -12,16 +14,22 @@
12
14
 
13
15
  ✅ Calculate over named dimensions using `s.cartesian { |v| puts "#{v.dim1} and #{v.dim2}" }` syntax
14
16
 
17
+ ✅ Add functions over dimensions using `s.add_function { |v| v.dim1 + v.dim2 }` syntax
18
+
15
19
  ✅ Lazy and eager evaluation
16
20
 
17
- ✅ Progress bars for large Cartesian combinations
21
+ ✅ Progress bars for large Cartesian combinations
18
22
 
19
- ✅ Export of Cartesian space to Markdown or CSV
23
+ ✅ Export of Cartesian space to Markdown or CSV
20
24
 
21
- ✅ Import of dimension space from JSON or YAML
25
+ ✅ Import of Cartesian space from JSON or YAML
26
+
27
+ ✅ Export of Cartesian space to Markdown or CSV
22
28
 
23
29
  ✅ Structured and colorized terminal output
24
30
 
31
+
32
+
25
33
  ## Installation
26
34
 
27
35
  ```bash
@@ -30,53 +38,103 @@ gem build flex-cartesian.gemspec
30
38
  gem install flex-cartesian-*.gem
31
39
  ```
32
40
 
41
+
42
+
33
43
  ## Usage
34
44
 
35
- ```ruby
45
+ ```
46
+ #!/usr/bin/ruby
47
+
36
48
  require 'flex-cartesian'
37
49
 
38
- # Define a Cartesian space with named dimensions:
50
+
51
+
52
+ # BASIC CONCEPTS
53
+
54
+ puts "\nDefine named dimensions"
39
55
  example = {
40
56
  dim1: [1, 2],
41
57
  dim2: ['x', 'y'],
42
58
  dim3: [true, false]
43
59
  }
60
+
61
+ puts "\nCreate Cartesian space"
44
62
  s = FlexCartesian.new(example)
45
63
 
46
- # Iterate over all combinations and calculate function on each combination:
47
- s.cartesian { |v| puts "#{v.dim1}-#{v.dim2}" if v.dim3 }
64
+ def do_something(v)
65
+ # do something here on vector v and its components
66
+ end
48
67
 
49
- # Get number of Cartesian combinations:
50
- puts "Total size: #{s.size}"
51
68
 
52
- # Convert Cartesian space to array of combinations
53
- array = s.to_a(limit: 3)
54
- puts array.inspect
55
69
 
56
- def do_something(v)
57
- end
70
+ # ITERATION OVER CARTESIAN SPACE
58
71
 
59
- # Display progress bar (useful for large Cartesian spaces)
72
+ puts "\nIterate over all Cartesian combinations and execute action (dimensionality-agnostic style)"
73
+ s.cartesian { |v| do_something(v) }
74
+
75
+ puts "\nIterate over all Cartesian combinations and execute action (dimensionality-aware style)"
76
+ s.cartesian { |v| puts "#{v.dim1} & #{v.dim2}" if v.dim3 }
77
+
78
+ puts "\nIterate and display progress bar (useful for large Cartesian spaces)"
60
79
  s.progress_each { |v| do_something(v) }
61
80
 
62
- # Print Cartesian space as table
63
- s.output(align: true)
81
+ puts "\nIterate in lLazy mode, without materializing entire Cartesian product in memory"
82
+ s.cartesian(lazy: true).take(2).each { |v| do_something(v) }
64
83
 
65
- # Lazy evaluation without materializing entire Cartesian product in memory:
66
- s.cartesian(lazy: true).take(2).each { |v| puts v.inspect }
67
84
 
68
- # Load from JSON or YAML
69
- File.write('example.json', JSON.pretty_generate(example))
70
- s = FlexCartesian.from_json('example.json')
85
+
86
+ # FUNCTIONS ON CARTESIAN SPACE
87
+
88
+ puts "\nAdd function 'triple'"
89
+ puts "Note: function is visualized in .output as a new dimension"
90
+ s.add_function(:triple) { |v| v.dim1 * 3 + (v.dim3 ? 1: 0) }
91
+ # Note: however, function remains a virtual construct, and it cannot be referenced by name
92
+ s.output
93
+
94
+ puts "\Add and then remove function 'test'"
95
+ s.add_function(:test) { |v| v.dim3.to_i }
96
+ s.remove_function(:test)
97
+
98
+
99
+
100
+ # PRINT
101
+
102
+ puts "\nPrint Cartesian space as plain table, all functions included"
71
103
  s.output
72
104
 
73
- # Export to Markdown
74
- s.output(format: :markdown, align: true)
105
+ puts "\nPrint Cartesian space as Markdown"
106
+ s.output(format: :markdown)
75
107
 
76
- # Export to CSV
108
+ puts "\nPrint Cartesian space as CSV"
77
109
  s.output(format: :csv)
110
+
111
+
112
+
113
+ # IMPORT / EXPORT
114
+
115
+ puts "\nImport Cartesian space from JSON (similar method for YAML)"
116
+ File.write('example.json', JSON.pretty_generate(example))
117
+ puts "\nNote: after import, all assigned functions will calculate again, and they appear in the output"
118
+ s.import('example.json').output
119
+
120
+ puts "\nExport Cartesian space to YAML (similar method for JSON)"
121
+ s.export('example.yaml', format: :yaml)
122
+
123
+
124
+
125
+ # UTILITIES
126
+
127
+ puts "\nGet number of Cartesian combinations"
128
+ puts "Note: .size counts only dimenstions, it ignores functions"
129
+ puts "Total size of Cartesian space: #{s.size}"
130
+
131
+ puts "\nPartially converting Cartesian space to array:"
132
+ array = s.to_a(limit: 3)
133
+ puts array.inspect
78
134
  ```
79
135
 
136
+
137
+
80
138
  ## API Overview
81
139
 
82
140
  ### Initialization
@@ -116,6 +174,33 @@ s.cartesian { |v| puts "#{v.dim1} - #{v.dim2}" }
116
174
 
117
175
  ---
118
176
 
177
+ ### Add / Remove Functions
178
+ ```ruby
179
+ add_function(name, &block)
180
+ remove_function(name)
181
+ ```
182
+ - `name`: symbol — the name of the virtual dimension (e.g. `:label`)
183
+ - `block`: a function that receives each vector and returns a computed value
184
+
185
+ Functions show up in `.output` like additional (virtual) dimensions.
186
+
187
+ Example:
188
+ ```ruby
189
+ s = FlexCartesian.new( { dim1: [1, 2], dim2: ['A', 'B'] } )
190
+ s.add_function(:increment) { |v| v.dim1 + 1 }
191
+
192
+ s.output(format: :markdown)
193
+ # | dim1 | dim2 | increment |
194
+ # |------|------|--------|
195
+ # | 1 | "A" | 2 |
196
+ # | 1 | "B" | 2 |
197
+ # ...
198
+ ```
199
+
200
+ > Note: functions are virtual — they are not part of the base dimensions, but they integrate seamlessly in output.
201
+
202
+ ---
203
+
119
204
  ### Count Total Combinations
120
205
  ```ruby
121
206
  size(dims = nil) → Integer
@@ -161,22 +246,36 @@ Markdown example:
161
246
 
162
247
  ---
163
248
 
164
- ### Load from JSON or YAML
249
+ ### Import from JSON or YAML
250
+ ```ruby
251
+ import('file.json',
252
+ format: :json) # or :yaml
253
+ ```
254
+
255
+ Obsolete import methods:
256
+ ```ruby
257
+ s.from_json("file.json")
258
+ s.from_yaml("file.yaml")
259
+ ```
260
+
261
+ ---
262
+
263
+ ### Export from JSON or YAML
165
264
  ```ruby
166
- FlexCartesian.from_json("file.json")
167
- FlexCartesian.from_yaml("file.yaml")
265
+ export('file.json',
266
+ format: :json) # or :yaml
168
267
  ```
169
268
 
170
269
  ---
171
270
 
172
- ### Output from Vectors
271
+ ### Print Cartesian Space
173
272
  Each yielded combination is a `Struct` extended with:
174
273
  ```ruby
175
- output(separator: " | ", colorize: false, align: false)
274
+ output(separator: " | ", colorize: false, align: true)
176
275
  ```
177
276
  Example:
178
277
  ```ruby
179
- s.cartesian { |v| v.output(colorize: true, align: true) }
278
+ s.cartesian { |v| v.output(colorize: true, align: false) }
180
279
  ```
181
280
 
182
281
  ## License
@@ -5,7 +5,7 @@ require 'json'
5
5
  require 'yaml'
6
6
 
7
7
  module FlexOutput
8
- def output(separator: " | ", colorize: false, align: false)
8
+ def output(separator: " | ", colorize: false, align: true)
9
9
  return puts "(empty struct)" unless respond_to?(:members) && respond_to?(:values)
10
10
 
11
11
  values_list = members.zip(values.map { |v| v.inspect })
@@ -35,6 +35,10 @@ class FlexCartesian
35
35
  @derived[name.to_sym] = block
36
36
  end
37
37
 
38
+ def remove_function(name)
39
+ @derived.delete(name.to_sym)
40
+ end
41
+
38
42
  def cartesian(dims = nil, lazy: false)
39
43
  dimensions = dims || @dimensions
40
44
  return nil unless dimensions.is_a?(Hash)
@@ -90,7 +94,7 @@ end
90
94
  end
91
95
  end
92
96
 
93
- def output(separator: " | ", colorize: false, align: false, format: :plain, limit: nil)
97
+ def output(separator: " | ", colorize: false, align: true, format: :plain, limit: nil)
94
98
  rows = []
95
99
  cartesian do |v|
96
100
  rows << v
@@ -123,14 +127,42 @@ end
123
127
  end
124
128
  end
125
129
 
126
- def self.from_json(path)
130
+ def import(path, format: :json)
131
+ data = case format
132
+ when :json
133
+ JSON.parse(File.read(path), symbolize_names: true)
134
+ when :yaml
135
+ YAML.safe_load(File.read(path), symbolize_names: true)
136
+ else
137
+ raise ArgumentError, "Unsupported format: #{format}. Only :json and :yaml are supported."
138
+ end
139
+
140
+ raise TypeError, "Expected parsed data to be a Hash" unless data.is_a?(Hash)
141
+
142
+ @dimensions = data
143
+ self
144
+ end
145
+
146
+ def export(path, format: :json)
147
+ case format
148
+ when :json
149
+ File.write(path, JSON.pretty_generate(@dimensions))
150
+ when :yaml
151
+ File.write(path, YAML.dump(@dimensions))
152
+ else
153
+ raise ArgumentError, "Unsupported format: #{format}. Only :json and :yaml are supported."
154
+ end
155
+ end
156
+
157
+
158
+ def from_json(path)
127
159
  data = JSON.parse(File.read(path), symbolize_names: true)
128
- new(data)
160
+ @dimensions = data
129
161
  end
130
162
 
131
- def self.from_yaml(path)
163
+ def from_yaml(path)
132
164
  data = YAML.safe_load(File.read(path), symbolize_names: true)
133
- new(data)
165
+ @dimensions = data
134
166
  end
135
167
 
136
168
  private
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: 0.1.8
4
+ version: 0.1.9
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-06 00:00:00.000000000 Z
11
+ date: 2025-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -53,9 +53,9 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.0'
55
55
  description: 'Flexible and human-friendly Cartesian product enumerator for Ruby. Supports
56
- calculated functions, dimension-agnostic iterators, named dimensions, tabular output,
57
- lazy/eager evaluation, progress bar, JSON/YAML loading, and export to Markdown/CSV.
58
- Code example: https://github.com/Yuri-Rassokhin/flex-cartesian/blob/main/README.md#usage'
56
+ functions on cartesian, dimensionality-agnostic/dimensionality-aware iterators,
57
+ named dimensions, tabular output, lazy/eager evaluation, progress bar, import from
58
+ JSON/YAML, and export to Markdown/CSV. Code example: https://github.com/Yuri-Rassokhin/flex-cartesian/blob/main/README.md#usage'
59
59
  email:
60
60
  - yuri.rassokhin@gmail.com
61
61
  executables: []