flex-cartesian 0.1.3 → 0.1.4
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/README.md +104 -2
- data/lib/golden.rb +137 -0
- metadata +4 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f3e10474552a7bfa80b189b46769b1dc621468b9a068918e42cce44d14879ab
|
4
|
+
data.tar.gz: 1dd5bea186d416ebb39bc6f74d268d271516cbbf945a9c3fbfa97d4682bf85bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eefbe47d1db3cf1e4316502de159d68963c633d72ea84fc38a378eefa235747845b8d7496d26534eeed6986e2e16cf9728366a1b3015e6e509f0c57a8ace5b3a
|
7
|
+
data.tar.gz: d4eaf78c1280145ad57841a984bde38b0f5f25b69845a59300877ed04ad6c48a2f325a144b6ff97aad6933fb9ed0b36bdc9b6c0c8156126fffd4a8c1d55aca32
|
data/README.md
CHANGED
@@ -24,10 +24,10 @@
|
|
24
24
|
|
25
25
|
## Installation
|
26
26
|
|
27
|
-
Install dependencies:
|
28
|
-
|
29
27
|
```bash
|
30
28
|
bundle install
|
29
|
+
gem build flex-cartesian.gemspec
|
30
|
+
gem install flex-cartesian-*.gem
|
31
31
|
```
|
32
32
|
|
33
33
|
## Usage
|
@@ -77,6 +77,108 @@ s.output(format: :markdown, align: true)
|
|
77
77
|
s.output(format: :csv)
|
78
78
|
```
|
79
79
|
|
80
|
+
## API Overview
|
81
|
+
|
82
|
+
### Initialization
|
83
|
+
```ruby
|
84
|
+
FlexCartesian.new(dimensions_hash)
|
85
|
+
```
|
86
|
+
- `dimensions_hash`: a hash with named dimensions; each value can be an `Enumerable` (e.g., arrays, ranges).
|
87
|
+
|
88
|
+
Example:
|
89
|
+
```ruby
|
90
|
+
dimensions = {
|
91
|
+
dim1: [1, 2],
|
92
|
+
dim2: ['x', 'y'],
|
93
|
+
dim3: [true, false]
|
94
|
+
}
|
95
|
+
|
96
|
+
FlexCartesian.new(dimensions)
|
97
|
+
```
|
98
|
+
|
99
|
+
---
|
100
|
+
|
101
|
+
### Iterate Over All Combinations
|
102
|
+
```ruby
|
103
|
+
# With block
|
104
|
+
cartesian(dims = nil, lazy: false) { |vector| ... }
|
105
|
+
|
106
|
+
# Without block: returns Enumerator
|
107
|
+
cartesian(dims = nil, lazy: false)
|
108
|
+
```
|
109
|
+
- `dims`: optional dimensions hash (default is the one provided at initialization).
|
110
|
+
- `lazy`: if true, returns a lazy enumerator.
|
111
|
+
|
112
|
+
Each combination is passed as a `Struct` with fields matching the dimension names:
|
113
|
+
```ruby
|
114
|
+
s.cartesian { |v| puts "#{v.dim1} - #{v.dim2}" }
|
115
|
+
```
|
116
|
+
|
117
|
+
---
|
118
|
+
|
119
|
+
### Count Total Combinations
|
120
|
+
```ruby
|
121
|
+
size(dims = nil) → Integer
|
122
|
+
```
|
123
|
+
Returns the number of possible combinations.
|
124
|
+
|
125
|
+
---
|
126
|
+
|
127
|
+
### Convert to Array
|
128
|
+
```ruby
|
129
|
+
to_a(limit: nil) → Array
|
130
|
+
```
|
131
|
+
- `limit`: maximum number of combinations to collect.
|
132
|
+
|
133
|
+
---
|
134
|
+
|
135
|
+
### Iterate with Progress Bar
|
136
|
+
```ruby
|
137
|
+
progress_each(dims = nil, lazy: false, title: "Processing") { |v| ... }
|
138
|
+
```
|
139
|
+
Displays a progress bar using `ruby-progressbar`.
|
140
|
+
|
141
|
+
---
|
142
|
+
|
143
|
+
### Print Table to Console
|
144
|
+
```ruby
|
145
|
+
output(
|
146
|
+
separator: " | ",
|
147
|
+
colorize: false,
|
148
|
+
align: false,
|
149
|
+
format: :plain # or :markdown, :csv
|
150
|
+
limit: nil
|
151
|
+
)
|
152
|
+
```
|
153
|
+
Prints all combinations in table form (plain/markdown/CSV).
|
154
|
+
Markdown example:
|
155
|
+
```
|
156
|
+
| dim1 | dim2 |
|
157
|
+
|------|------|
|
158
|
+
| 1 | "a" |
|
159
|
+
| 2 | "b" |
|
160
|
+
```
|
161
|
+
|
162
|
+
---
|
163
|
+
|
164
|
+
### Load from JSON or YAML
|
165
|
+
```ruby
|
166
|
+
FlexCartesian.from_json("file.json")
|
167
|
+
FlexCartesian.from_yaml("file.yaml")
|
168
|
+
```
|
169
|
+
|
170
|
+
---
|
171
|
+
|
172
|
+
### Output from Vectors
|
173
|
+
Each yielded combination is a `Struct` extended with:
|
174
|
+
```ruby
|
175
|
+
output(separator: " | ", colorize: false, align: false)
|
176
|
+
```
|
177
|
+
Example:
|
178
|
+
```ruby
|
179
|
+
s.cartesian { |v| v.output(colorize: true, align: true) }
|
180
|
+
```
|
181
|
+
|
80
182
|
## License
|
81
183
|
|
82
184
|
This project is licensed under the terms of the GNU General Public License v3.0.
|
data/lib/golden.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'progressbar'
|
3
|
+
require 'colorize'
|
4
|
+
require 'json'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module FlexOutput
|
8
|
+
def output(separator: " | ", colorize: false, align: false)
|
9
|
+
return puts "(empty struct)" unless respond_to?(:members) && respond_to?(:values)
|
10
|
+
|
11
|
+
values_list = members.zip(values.map { |v| v.inspect })
|
12
|
+
|
13
|
+
# calculate widths, if align required
|
14
|
+
widths = align ? values_list.map { |k, v| [k.to_s.size, v.size].max } : []
|
15
|
+
|
16
|
+
line = values_list.each_with_index.map do |(_, val), i|
|
17
|
+
str = val.to_s
|
18
|
+
str = str.ljust(widths[i]) if align
|
19
|
+
colorize ? str.colorize(:cyan) : str
|
20
|
+
end
|
21
|
+
|
22
|
+
puts line.join(separator)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class FlexCartesian
|
27
|
+
attr :dimensions
|
28
|
+
|
29
|
+
def initialize(dimensions = nil)
|
30
|
+
@dimensions = dimensions
|
31
|
+
end
|
32
|
+
|
33
|
+
def cartesian(dims = nil, lazy: false)
|
34
|
+
dimensions = dims || @dimensions
|
35
|
+
return nil unless dimensions.is_a?(Hash)
|
36
|
+
|
37
|
+
names = dimensions.keys
|
38
|
+
values = dimensions.values.map { |dim| dim.is_a?(Enumerable) ? dim.to_a : [dim] }
|
39
|
+
|
40
|
+
return to_enum(:cartesian, dims, lazy: lazy) unless block_given?
|
41
|
+
return if values.any?(&:empty?)
|
42
|
+
|
43
|
+
struct_class = Struct.new(*names).tap { |sc| sc.include(FlexOutput) }
|
44
|
+
|
45
|
+
base = values.first.product(*values[1..])
|
46
|
+
enum = lazy ? base.lazy : base
|
47
|
+
|
48
|
+
enum.each do |combo|
|
49
|
+
yield struct_class.new(*combo)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def size(dims = nil)
|
54
|
+
dimensions = dims || @dimensions
|
55
|
+
return 0 unless dimensions.is_a?(Hash)
|
56
|
+
|
57
|
+
values = dimensions.values.map { |dim| dim.is_a?(Enumerable) ? dim.to_a : [dim] }
|
58
|
+
return 0 if values.any?(&:empty?)
|
59
|
+
|
60
|
+
values.map(&:size).inject(1, :*)
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_a(limit: nil)
|
64
|
+
result = []
|
65
|
+
cartesian do |v|
|
66
|
+
result << v
|
67
|
+
break if limit && result.size >= limit
|
68
|
+
end
|
69
|
+
result
|
70
|
+
end
|
71
|
+
|
72
|
+
def progress_each(dims = nil, lazy: false, title: "Processing")
|
73
|
+
total = size(dims)
|
74
|
+
bar = ProgressBar.create(title: title, total: total, format: '%t [%B] %p%% %e')
|
75
|
+
|
76
|
+
cartesian(dims, lazy: lazy) do |v|
|
77
|
+
yield v
|
78
|
+
bar.increment
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def output(separator: " | ", colorize: false, align: false, format: :plain, limit: nil)
|
83
|
+
rows = []
|
84
|
+
cartesian do |v|
|
85
|
+
rows << v
|
86
|
+
break if limit && rows.size >= limit
|
87
|
+
end
|
88
|
+
return if rows.empty?
|
89
|
+
|
90
|
+
headers = rows.first.members.map(&:to_s)
|
91
|
+
|
92
|
+
# Get widths
|
93
|
+
widths = align ? headers.to_h { |h|
|
94
|
+
[h, [h.size, *rows.map { |r| fmt_cell(r[h], false).size }].max]
|
95
|
+
} : {}
|
96
|
+
|
97
|
+
# Title
|
98
|
+
case format
|
99
|
+
when :markdown
|
100
|
+
puts "| " + headers.map { |h| h.ljust(widths[h] || h.size) }.join(" | ") + " |"
|
101
|
+
puts "|-" + headers.map { |h| "-" * (widths[h] || h.size) }.join("-|-") + "-|"
|
102
|
+
when :csv
|
103
|
+
puts headers.join(",")
|
104
|
+
else
|
105
|
+
puts headers.map { |h| fmt_cell(h, colorize, widths[h]) }.join(separator)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Rows
|
109
|
+
rows.each do |row|
|
110
|
+
line = headers.map { |h| fmt_cell(row[h], colorize, widths[h]) }
|
111
|
+
puts format == :csv ? line.join(",") : line.join(separator)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.from_json(path)
|
116
|
+
data = JSON.parse(File.read(path), symbolize_names: true)
|
117
|
+
new(data)
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.from_yaml(path)
|
121
|
+
data = YAML.safe_load(File.read(path), symbolize_names: true)
|
122
|
+
new(data)
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def fmt_cell(value, colorize, width = nil)
|
128
|
+
str = case value
|
129
|
+
when String then value # rows - without inspect
|
130
|
+
else value.inspect # the rest is good to inspect
|
131
|
+
end
|
132
|
+
str = str.ljust(width) if width
|
133
|
+
colorize ? str.colorize(:cyan) : str
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
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.
|
4
|
+
version: 0.1.4
|
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-
|
11
|
+
date: 2025-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -52,26 +52,8 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '2.0'
|
55
|
-
-
|
56
|
-
name: yaml
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
description: |
|
70
|
-
Flexible and human-friendly Cartesian product enumerator for Ruby.
|
71
|
-
Supports dimension-agnostic iteration, named dimensions, structured output,
|
55
|
+
description: Supports dimension-agnostic iterators, named dimensions, tabular output,
|
72
56
|
lazy/eager evaluation, progress bar, JSON/YAML loading, and export to Markdown/CSV.
|
73
|
-
|
74
|
-
Code example: https://github.com/Yuri-Rassokhin/flex-cartesian/blob/main/README.md#usage
|
75
57
|
email:
|
76
58
|
- yuri.rassokhin@gmail.com
|
77
59
|
executables: []
|
@@ -82,6 +64,7 @@ files:
|
|
82
64
|
- LICENSE
|
83
65
|
- README.md
|
84
66
|
- lib/flex-cartesian.rb
|
67
|
+
- lib/golden.rb
|
85
68
|
homepage: https://github.com/Yuri-Rassokhin/flex-cartesian
|
86
69
|
licenses:
|
87
70
|
- GPL-3.0
|