mortadella 1.0.0 → 1.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: addead2f5fd8242211b456117c6473d64afbbd62
4
- data.tar.gz: 9184b1d1774cd478d4fb1772be9e4b4a68429f3d
2
+ SHA256:
3
+ metadata.gz: 89f81d195a7c95dc3c7a9481087b7b82a8e099c86db2245da940233ff2c0a76f
4
+ data.tar.gz: 38a0f7e70a8fd87234b71b09fe2b622262c024fedf9be2ebc1f8e0e663a3f72f
5
5
  SHA512:
6
- metadata.gz: a508525b3f43f28b7b30e419eb4e24857c3e9eab229ab94ec7fc97fb17b4a6337edf8687de6b8f8acadc2159c76d056162dd335346262a5bf3c1e85d381bab34
7
- data.tar.gz: 06e1f982f1a0d0630ac771431c29cdc668f0dffd507b08c8e746f058cd757008ceb8cb1b35bd4abd86dd2900a17af63a51a03067f78ac8cca8ec70bc15121206
6
+ metadata.gz: '083bbf046a76c7f6ea292b6705f899fcd6f79f44a4905aed0d2f84da806d92c9dd7758c448b5a6712c6ea9729ef1ac3fff0b9aa0b00787f7452a7688f0b5d314'
7
+ data.tar.gz: 44ffd063b09507b25f49f8c4164cea2b1a1b974f5311511c85882b73d4c444fe302e740bca5db681c6fcce53a2528e267b0b88fef9d84b833013058c7cdb490b
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+ branches: ["main"]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ ruby-version: ["3.4"]
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: dprint/check@v2.2
21
+ - uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby-version }}
24
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
25
+ - run: bundle exec rake
26
+ - run: bundle exec rake fix
27
+ - run: git diff HEAD --exit-code --color
28
+ - uses: coverallsapp/github-action@v2
data/.rubocop.yml CHANGED
@@ -1,35 +1,16 @@
1
1
  AllCops:
2
-
2
+ NewCops: enable
3
3
  DisplayCopNames: true
4
-
5
4
  DisplayStyleGuide: true
6
-
7
5
  Include:
8
- - '**/Rakefile'
9
-
6
+ - "**/Rakefile"
7
+ SuggestExtensions: false
10
8
 
11
- Lint/Eval:
12
- Enabled: false
13
-
14
-
15
- Metrics/LineLength:
9
+ Layout/LineLength:
16
10
  Max: 100
17
11
 
12
+ Style/StringLiterals:
13
+ EnforcedStyle: double_quotes
18
14
 
19
- Style/AccessModifierIndentation:
20
- EnforcedStyle: outdent
21
-
22
- Style/EmptyLines:
23
- Enabled: false
24
-
25
- Style/EmptyLinesAroundClassBody:
26
- EnforcedStyle: empty_lines
27
-
28
- Style/EmptyLinesAroundModuleBody:
29
- EnforcedStyle: empty_lines
30
-
31
-
32
-
33
- Style/MethodDefParentheses:
34
- EnforcedStyle: require_no_parentheses
35
-
15
+ Style/SymbolArray:
16
+ EnforcedStyle: brackets
data/CHANGELOG.md ADDED
@@ -0,0 +1,36 @@
1
+ # CHANGELOG
2
+
3
+ ## 1.2.0 (2025-11-04)
4
+
5
+ - Add ability to hash tables
6
+ - Verify argument types
7
+ - Add YARD type signatures
8
+ - Improved dry-up algorithm
9
+ - Validate the length of added rows
10
+
11
+ ## 1.1.0 (2016-08-25)
12
+
13
+ - Keep matching columns functionality to filter tables
14
+
15
+ ## 1.0.0 (2015-12-22)
16
+
17
+ - Stable release with improved API stability
18
+ - Emptiness checking for vertical tables
19
+
20
+ ## 0.2.2 (2015-12-09)
21
+
22
+ - Limited visibility of internal methods
23
+
24
+ ## 0.2.1 (2015-10-18)
25
+
26
+ - Better require support for easier gem loading
27
+
28
+ ## 0.2.0 (2022-10-18)
29
+
30
+ - Vertical tables
31
+
32
+ ## 0.1.0 (2015-06-02)
33
+
34
+ - Horizontal table support with headers and rows
35
+ - Dry-up functionality for repeated values
36
+ - Cucumber table compatibility
data/DEVELOPMENT.md ADDED
@@ -0,0 +1,16 @@
1
+ # Developer guidelines
2
+
3
+ - set up local environment: `bundle install`
4
+ - run all tests: `rake` (or `rake default`)
5
+ - run linters: `rake lint`
6
+ - auto-fix all issues: `rake fix`
7
+ - run tests only: `rake features`
8
+
9
+ ## Release a new version to RubyGems
10
+
11
+ - in a branch:
12
+ - update CHANGELOG.md
13
+ - search and replace all occurrences of `1.2.0`
14
+ - run `bundle install`
15
+ - ship this branch
16
+ - push a new version to Rubygems: `rake release`
data/Gemfile CHANGED
@@ -1,4 +1,14 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in mortadella.gemspec
4
6
  gemspec
7
+
8
+ gem "bundler"
9
+ gem "cucumber"
10
+ gem "logger"
11
+ gem "rake"
12
+ gem "rspec"
13
+ gem "rubocop"
14
+ gem "simplecov"
data/Gemfile.lock CHANGED
@@ -1,97 +1,107 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mortadella (1.0.0)
4
+ mortadella (1.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- ast (2.2.0)
10
- astrolabe (1.3.1)
11
- parser (~> 2.2)
12
- builder (3.2.2)
13
- coveralls (0.8.10)
14
- json (~> 1.8)
15
- rest-client (>= 1.6.8, < 2)
16
- simplecov (~> 0.11.0)
17
- term-ansicolor (~> 1.3)
18
- thor (~> 0.19.1)
19
- tins (~> 1.6.0)
20
- cucumber (2.1.0)
21
- builder (>= 2.1.2)
22
- cucumber-core (~> 1.3.0)
23
- diff-lcs (>= 1.1.3)
24
- gherkin3 (~> 3.1.0)
25
- multi_json (>= 1.7.5, < 2.0)
26
- multi_test (>= 0.1.2)
27
- cucumber-core (1.3.1)
28
- gherkin3 (~> 3.1.0)
29
- diff-lcs (1.2.5)
30
- docile (1.1.5)
31
- domain_name (0.5.25)
32
- unf (>= 0.0.5, < 1.0.0)
33
- gherkin3 (3.1.2)
34
- http-cookie (1.0.2)
35
- domain_name (~> 0.5)
36
- json (1.8.3)
37
- mime-types (2.99)
38
- multi_json (1.11.2)
39
- multi_test (0.1.2)
40
- netrc (0.11.0)
41
- parser (2.2.3.0)
42
- ast (>= 1.1, < 3.0)
43
- powerpack (0.1.1)
44
- rainbow (2.0.0)
45
- rake (10.4.2)
46
- rest-client (1.8.0)
47
- http-cookie (>= 1.0.2, < 2.0)
48
- mime-types (>= 1.16, < 3.0)
49
- netrc (~> 0.7)
50
- rspec (3.4.0)
51
- rspec-core (~> 3.4.0)
52
- rspec-expectations (~> 3.4.0)
53
- rspec-mocks (~> 3.4.0)
54
- rspec-core (3.4.1)
55
- rspec-support (~> 3.4.0)
56
- rspec-expectations (3.4.0)
9
+ ast (2.4.3)
10
+ bigdecimal (3.1.9)
11
+ builder (3.3.0)
12
+ cucumber (9.2.1)
13
+ builder (~> 3.2)
14
+ cucumber-ci-environment (> 9, < 11)
15
+ cucumber-core (> 13, < 14)
16
+ cucumber-cucumber-expressions (~> 17.0)
17
+ cucumber-gherkin (> 24, < 28)
18
+ cucumber-html-formatter (> 20.3, < 22)
19
+ cucumber-messages (> 19, < 25)
20
+ diff-lcs (~> 1.5)
21
+ mini_mime (~> 1.1)
22
+ multi_test (~> 1.1)
23
+ sys-uname (~> 1.2)
24
+ cucumber-ci-environment (10.0.1)
25
+ cucumber-core (13.0.3)
26
+ cucumber-gherkin (>= 27, < 28)
27
+ cucumber-messages (>= 20, < 23)
28
+ cucumber-tag-expressions (> 5, < 7)
29
+ cucumber-cucumber-expressions (17.1.0)
30
+ bigdecimal
31
+ cucumber-gherkin (27.0.0)
32
+ cucumber-messages (>= 19.1.4, < 23)
33
+ cucumber-html-formatter (21.9.0)
34
+ cucumber-messages (> 19, < 28)
35
+ cucumber-messages (22.0.0)
36
+ cucumber-tag-expressions (6.1.2)
37
+ diff-lcs (1.6.0)
38
+ docile (1.4.1)
39
+ ffi (1.17.1)
40
+ json (2.10.2)
41
+ language_server-protocol (3.17.0.4)
42
+ lint_roller (1.1.0)
43
+ logger (1.6.6)
44
+ mini_mime (1.1.5)
45
+ multi_test (1.1.0)
46
+ parallel (1.26.3)
47
+ parser (3.3.7.1)
48
+ ast (~> 2.4.1)
49
+ racc
50
+ racc (1.8.1)
51
+ rainbow (3.1.1)
52
+ rake (13.2.1)
53
+ regexp_parser (2.10.0)
54
+ rspec (3.13.0)
55
+ rspec-core (~> 3.13.0)
56
+ rspec-expectations (~> 3.13.0)
57
+ rspec-mocks (~> 3.13.0)
58
+ rspec-core (3.13.3)
59
+ rspec-support (~> 3.13.0)
60
+ rspec-expectations (3.13.3)
57
61
  diff-lcs (>= 1.2.0, < 2.0)
58
- rspec-support (~> 3.4.0)
59
- rspec-mocks (3.4.0)
62
+ rspec-support (~> 3.13.0)
63
+ rspec-mocks (3.13.2)
60
64
  diff-lcs (>= 1.2.0, < 2.0)
61
- rspec-support (~> 3.4.0)
62
- rspec-support (3.4.1)
63
- rubocop (0.35.1)
64
- astrolabe (~> 1.3)
65
- parser (>= 2.2.3.0, < 3.0)
66
- powerpack (~> 0.1)
67
- rainbow (>= 1.99.1, < 3.0)
65
+ rspec-support (~> 3.13.0)
66
+ rspec-support (3.13.2)
67
+ rubocop (1.74.0)
68
+ json (~> 2.3)
69
+ language_server-protocol (~> 3.17.0.2)
70
+ lint_roller (~> 1.1.0)
71
+ parallel (~> 1.10)
72
+ parser (>= 3.3.0.2)
73
+ rainbow (>= 2.2.2, < 4.0)
74
+ regexp_parser (>= 2.9.3, < 3.0)
75
+ rubocop-ast (>= 1.38.0, < 2.0)
68
76
  ruby-progressbar (~> 1.7)
69
- tins (<= 1.6.0)
70
- ruby-progressbar (1.7.5)
71
- simplecov (0.11.1)
72
- docile (~> 1.1.0)
73
- json (~> 1.8)
74
- simplecov-html (~> 0.10.0)
75
- simplecov-html (0.10.0)
76
- term-ansicolor (1.3.2)
77
- tins (~> 1.0)
78
- thor (0.19.1)
79
- tins (1.6.0)
80
- unf (0.1.4)
81
- unf_ext
82
- unf_ext (0.0.7.1)
77
+ unicode-display_width (>= 2.4.0, < 4.0)
78
+ rubocop-ast (1.40.0)
79
+ parser (>= 3.3.1.0)
80
+ ruby-progressbar (1.13.0)
81
+ simplecov (0.22.0)
82
+ docile (~> 1.1)
83
+ simplecov-html (~> 0.11)
84
+ simplecov_json_formatter (~> 0.1)
85
+ simplecov-html (0.13.1)
86
+ simplecov_json_formatter (0.1.4)
87
+ sys-uname (1.3.1)
88
+ ffi (~> 1.1)
89
+ unicode-display_width (3.1.4)
90
+ unicode-emoji (~> 4.0, >= 4.0.4)
91
+ unicode-emoji (4.0.4)
83
92
 
84
93
  PLATFORMS
85
94
  ruby
86
95
 
87
96
  DEPENDENCIES
88
97
  bundler
89
- coveralls
90
98
  cucumber
99
+ logger
91
100
  mortadella!
92
101
  rake
93
102
  rspec
94
103
  rubocop
104
+ simplecov
95
105
 
96
106
  BUNDLED WITH
97
- 1.10.6
107
+ 2.6.6
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015 Originate
1
+ Copyright (c) 2015 Kevin Goslar
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,37 +1,30 @@
1
- # Delicious Mock Ruby Tables
1
+ # Mortadella for Ruby
2
2
 
3
- [![Build Status](https://circleci.com/gh/Originate/mortadella/tree/master.svg?style=shield)](https://circleci.com/gh/Originate/mortadella)
4
- [![Code Climate](https://codeclimate.com/github/Originate/mortadella/badges/gpa.svg)](https://codeclimate.com/github/Originate/mortadella)
5
- [![Coverage Status](https://coveralls.io/repos/Originate/mortadella/badge.svg?branch=master&service=github)](https://coveralls.io/github/Originate/mortadella?branch=master)
6
- [![Dependency Status](https://gemnasium.com/Originate/mortadella.svg)](https://gemnasium.com/Originate/mortadella)
3
+ [![CI](https://github.com/kevgo/mortadella-ruby/actions/workflows/ruby.yml/badge.svg)](https://github.com/kevgo/mortadella-ruby/actions/workflows/ruby.yml)
4
+ [![Coverage Status](https://coveralls.io/repos/github/kevgo/mortadella-ruby/badge.svg?branch=main)](https://coveralls.io/github/kevgo/mortadella-ruby?branch=main)
7
5
 
6
+ Mortadella for Ruby makes it easy to programmatically build data tables that can
7
+ be compared to [Cucumber for Ruby](https://github.com/cucumber/cucumber-ruby)
8
+ tables through `cucumber_table.diff! mortadella_table`.
8
9
 
9
- Mortadella makes it easy to programmatically build data tables
10
- that can be compared to Cucumber tables
11
- through `cucumber_table.diff! mortadella_table`.
12
-
13
- You want to do this as much as possible.
14
- Cucumber has very powerful built-in facilities
15
- to visualize where and how two tables differ.
16
-
17
- <img src="http://blog.originate.com/mortadella/ingredients2.png" >
18
- _Oh no, our algorithm selected too many apples!_
10
+ You want to do this as much as possible. Cucumber for Ruby has very powerful
11
+ built-in facilities to visualize where and how two tables differ:
19
12
 
13
+ <img src="https://raw.githubusercontent.com/kevgo/mortadella/master/documentation/ingredients.png" width="292" height="139">
14
+ <i>Oh no, our algorithm selected too many apples!</i>
20
15
 
21
16
  ## Installation
22
17
 
23
- * add `gem 'mortadella'` to your `Gemfile`
24
- * run `bundle`
25
-
18
+ - add `gem 'mortadella'` to your `Gemfile`
19
+ - run `bundle install`
26
20
 
27
21
  ## Usage
28
22
 
29
23
  Mortadella supports horizontal and vertical Cucumber tables.
30
24
 
31
-
32
25
  ### Horizontal Tables
33
26
 
34
- * In your cucumber spec, define the expected data in table form
27
+ - In your cucumber spec, define the expected data in table form
35
28
 
36
29
  ```cucumber
37
30
  Then I have these ingredients
@@ -41,8 +34,8 @@ Mortadella supports horizontal and vertical Cucumber tables.
41
34
  | apples | 3 pc |
42
35
  ```
43
36
 
44
- * in the step definition for this, build an equivalent Mortadella table with the actual data,
45
- and diff the Cucumber table with the expected data against it.
37
+ - in the step definition for this, build an equivalent Mortadella table with the
38
+ actual data, and diff the Cucumber table with the expected data against it.
46
39
 
47
40
  ```ruby
48
41
  Then /^I have these ingredients$/ do |expected_ingredients|
@@ -54,14 +47,24 @@ Mortadella supports horizontal and vertical Cucumber tables.
54
47
  end
55
48
  ```
56
49
 
57
- * you can also
58
- [dry up repetitive fields](https://github.com/Originate/mortadella/blob/master/features/horizontal_tables/drying_up_fields.feature)
59
- for better readability
50
+ - you can also
51
+ [dry up repetitive fields](https://github.com/kevgo/mortadella/blob/master/features/horizontal_tables/drying_up_fields.feature)
52
+ for better readability:
60
53
 
54
+ ```cucumber
55
+ | DAY | ACTIVITY |
56
+ | Monday | mowing |
57
+ | | musing |
58
+ | Tuesday | typing |
59
+ | | tutoring |
60
+ ```
61
+
62
+ - or filter the columns of your finished table by calling
63
+ [keep_matching_columns](features/horizontal_tables/keep_matching_columns.feature)
61
64
 
62
65
  ### Vertical Tables
63
66
 
64
- * In your cucumber spec, define the expected data in table form
67
+ - In your cucumber spec, define the expected data in table form
65
68
 
66
69
  ```cucumber
67
70
  Then my pie conforms to these specs:
@@ -70,8 +73,8 @@ Mortadella supports horizontal and vertical Cucumber tables.
70
73
  | CALORIES | 500 |
71
74
  ```
72
75
 
73
- * in the step definition for this, build an equivalent Mortadella table with the actual data,
74
- and diff the Cucumber table with the expected data against it.
76
+ - in the step definition for this, build an equivalent Mortadella table with the
77
+ actual data, and diff the Cucumber table with the expected data against it.
75
78
 
76
79
  ```ruby
77
80
  Then /^My pie has these metrics:$/ do |expected_metrics|
@@ -83,13 +86,21 @@ Mortadella supports horizontal and vertical Cucumber tables.
83
86
  end
84
87
  ```
85
88
 
89
+ ## API Reference
90
+
91
+ ### Horizontal Tables
86
92
 
87
- ## Development
93
+ - `new(headers:, dry: [])` - Create a new horizontal table with column headers
94
+ - `<<(row)` - Add a row to the table
95
+ - `empty?` - Check if the table has no data rows
96
+ - `keep_matching_columns(columns)` - Filter table to only keep specified columns
97
+ - `table` - Access the raw Cucumber-compatible table array
98
+
99
+ ### Vertical Tables
88
100
 
89
- * set up local environment: `bundle install`
90
- * run all tests: `bundle exec rake`
91
- * run linter only: `rake lint`
92
- * run tests only: `rake features`
93
- * publish a new gem:
94
- * update the version in [mortadella.gemspec](mortadella.gemspec)
95
- * `rake release`
101
+ - `new` - Create a new empty vertical table
102
+ - `[key] = value` - Add a key-value pair to the table
103
+ - `empty?` - Check if the table has no rows
104
+ - `key?(header)` - Check if a header exists in the table
105
+ - `to_h` - Convert the table to a Ruby hash
106
+ - `table` - Access the raw Cucumber-compatible table array
data/Rakefile CHANGED
@@ -1,12 +1,24 @@
1
- require 'bundler'
2
- require 'bundler/gem_tasks'
3
- require 'cucumber'
4
- require 'cucumber/rake/task'
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler"
4
+ require "bundler/gem_tasks"
5
+ require "cucumber"
6
+ require "cucumber/rake/task"
7
+
8
+ # Files to lint and format
9
+ RUBY_FILES = "lib/*.rb lib/**/*.rb mortadella.gemspec Rakefile"
5
10
 
6
11
  Cucumber::Rake::Task.new :features
7
- task default: %i(lint features)
12
+ task default: [:lint, :features]
13
+
14
+ desc "Fix all auto-fixable issues"
15
+ task "fix" do
16
+ sh "bundle exec rubocop -A #{RUBY_FILES}"
17
+ sh "dprint fmt"
18
+ end
8
19
 
9
- desc 'Run linter'
10
- task 'lint' do
11
- sh 'bundle exec rubocop'
20
+ desc "Run linters"
21
+ task "lint" do
22
+ sh "bundle exec rubocop #{RUBY_FILES}"
23
+ sh "dprint check"
12
24
  end
data/cucumber.yml ADDED
@@ -0,0 +1 @@
1
+ default: --publish-quiet
Binary file
data/dprint.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "markdown": {
3
+ "textWrap": "always"
4
+ },
5
+ "toml": {},
6
+ "yaml": {},
7
+ "excludes": ["vendor"],
8
+ "plugins": [
9
+ "https://plugins.dprint.dev/markdown-0.20.0.wasm",
10
+ "https://plugins.dprint.dev/toml-0.7.0.wasm",
11
+ "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm"
12
+ ]
13
+ }
@@ -1,19 +1,11 @@
1
1
  Feature: Creating mock data tables
2
2
 
3
- As a Cucumber user
4
- I want to programmatically create horizontal mock data tables from application data
5
- So that I can use Cucumber's built-in table diffing to verify my application data ergonomically.
6
-
7
-
8
3
  Scenario: Creating a simple data table
9
4
  Given I create a horizontal Mortadella instance: "m = Mortadella::Horizontal.new headers: ['DAY', 'ACTIVITY']"
10
5
  And I add a data row: "m << ['Monday', 'mowing']"
11
6
  And I add another data row: "m << ['Tuesday', 'tutoring']"
12
- And I add another data row: "m << ['Wednesday', 'welcoming']"
13
7
  When I request the instance data table "m.table"
14
8
  Then Mortadella returns an object that matches this Cucumber table
15
- | DAY | ACTIVITY |
16
- | Monday | mowing |
17
- | Tuesday | tutoring |
18
- | Wednesday | welcoming |
19
-
9
+ | DAY | ACTIVITY |
10
+ | Monday | mowing |
11
+ | Tuesday | tutoring |
@@ -1,28 +1,15 @@
1
1
  Feature: Drying up repetitive fields
2
2
 
3
- As a developer with a lot of repetitive data in my Cucumber tables
4
- I want that redundant elements are omitted from my table
5
- So that I can see better how data in my table is grouped and where it changes.
6
-
7
-
8
3
  Scenario: drying up repetitive columns
9
- Given I have a Mortadella instance with a DRY column: "m = Mortadella::Horizontal.new headers: ['DAY', 'ACTIVITY'], dry: ['DAY']"
10
-
11
- And I add an activity for Monday: "m << ['Monday', 'mowing']"
12
- And I add another activity for Monday: "m << ['Monday', 'musing']"
13
- And I add another activity for Monday: "m << ['Monday', 'mentoring']"
14
-
15
- And I add an activity for Tuesday: "m << ['Tuesday', 'typing']"
16
- And I add another activity for Tuesday: "m << ['Tuesday', 'tutoring']"
17
- And I add another activity for Tuesday: "m << ['Tuesday', 'throwing']"
18
-
19
- When I request the instance data table "m.table"
4
+ Given I have a Mortadella instance with a DRY column: "m = Mortadella::Horizontal.new headers: ['DAY', 'ACTIVITY'], dry: ['DAY']"
5
+ And I add an activity for Monday: "m << ['Monday', 'mowing']"
6
+ And I add another activity for Monday: "m << ['Monday', 'musing']"
7
+ And I add an activity for Tuesday: "m << ['Tuesday', 'typing']"
8
+ And I add another activity for Tuesday: "m << ['Tuesday', 'tutoring']"
9
+ When I request the instance data table "m.table"
20
10
  Then Mortadella returns a table with repeated day names cleared out for better readability
21
- | DAY | ACTIVITY |
22
- | Monday | mowing |
23
- | | musing |
24
- | | mentoring |
25
- | Tuesday | typing |
26
- | | tutoring |
27
- | | throwing |
28
-
11
+ | DAY | ACTIVITY |
12
+ | Monday | mowing |
13
+ | | musing |
14
+ | Tuesday | typing |
15
+ | | tutoring |
@@ -1,18 +1,12 @@
1
1
  Feature: Verifying emptiness
2
2
 
3
- As a Cucumber user
4
- I want a programmatic way to verify emptiness of a Mortadella instance
5
- So that I can verify the absence of data in comfortable ways.
6
-
7
-
8
3
  Scenario: an empty table
9
- Given I have a Mortadella instance: "m = Mortadella::Horizontal.new headers: ['foo']"
10
- When I ask it whether it is empty: "m.empty?"
4
+ Given I have a Mortadella instance: "m = Mortadella::Horizontal.new headers: ['foo']"
5
+ When I ask it whether it is empty: "m.empty?"
11
6
  Then it responds with true
12
7
 
13
-
14
8
  Scenario: a non-empty table
15
- Given I have a Mortadella instance: "m = Mortadella::Horizontal.new headers: ['foo']"
16
- And I add a data row: "m << ['bar']"
17
- When I ask it whether it is empty: "m.empty?"
9
+ Given I have a Mortadella instance: "m = Mortadella::Horizontal.new headers: ['foo']"
10
+ And I add a data row: "m << ['bar']"
11
+ When I ask it whether it is empty: "m.empty?"
18
12
  Then it responds with false
@@ -0,0 +1,12 @@
1
+ Feature: removing empty rows
2
+
3
+ Scenario: filtering multiple columns
4
+ Given I create a horizontal Mortadella instance: "m = Mortadella::Horizontal.new headers: ['DAY', 'ACTIVITY', 'HIGH-SCORE', 'AVERAGE']"
5
+ And I add a data row: "m << ['Monday', 'mowing', '1.0', '0.5']"
6
+ And I add another data row: "m << ['Tuesday', 'tutoring', '2.0', '1.1']"
7
+ When I filter column names: "m.keep_matching_columns ['DAY', 'HIGH-SCORE']"
8
+ And I request the instance data table "m.table"
9
+ Then Mortadella returns an object that matches this Cucumber table
10
+ | DAY | HIGH-SCORE |
11
+ | Monday | 1.0 |
12
+ | Tuesday | 2.0 |
@@ -1,14 +1,13 @@
1
- Given(/^I (?:add|ask|create|have|request) .+? "(.+?)"$/) do |code|
2
- @result = eval "@#{code}"
3
- end
4
-
1
+ # frozen_string_literal: true
5
2
 
3
+ Given(/^I (?:add|ask|create|filter|have|request) .+? "(.+?)"$/) do |code|
4
+ @result = eval("@#{code}")
5
+ end
6
6
 
7
7
  Then(/^Mortadella returns/) do |table|
8
- table.diff! @result
8
+ table.diff!(@result)
9
9
  end
10
10
 
11
-
12
11
  Then(/^it responds with (.+?)$/) do |code|
13
- @result = eval "@#{code}"
12
+ @result = eval("@#{code}")
14
13
  end
@@ -1,8 +1,11 @@
1
- if ENV['CI']
2
- require 'coveralls'
3
- Coveralls.wear!
1
+ # frozen_string_literal: true
2
+
3
+ require "simplecov"
4
+ SimpleCov.start do
5
+ enable_coverage :branch
6
+ add_filter "/features/"
4
7
  end
5
8
 
6
- require 'bundler/setup'
9
+ require "bundler/setup"
7
10
  Bundler.setup
8
- require 'mortadella'
11
+ require "mortadella"
@@ -1,18 +1,10 @@
1
1
  Feature: Creating vertical mock data tables
2
2
 
3
- As a Cucumber user
4
- I want to programmatically create vertical mock data tables from application data
5
- So that I can use Cucumber's built-in table diffing to verify my application data ergonomically.
6
-
7
-
8
3
  Scenario: Creating a simple data table
9
4
  Given I create a vertical Mortadella instance: "m = Mortadella::Vertical.new"
10
- And I add a data row: "m['NAME'] = 'Mortadella'"
11
- And I add another data row: "m['TYPE'] = 'Ruby Gem'"
12
- And I add another data row: "m['AUTHOR'] = 'Kevin Goslar'"
13
- When I request the instance data table "m.table"
5
+ And I add a data row: "m['NAME'] = 'Mortadella'"
6
+ And I add another data row: "m['TYPE'] = 'Ruby Gem'"
7
+ When I request the instance data table "m.table"
14
8
  Then Mortadella returns an object that matches this Cucumber table
15
- | NAME | Mortadella |
16
- | TYPE | Ruby Gem |
17
- | AUTHOR | Kevin Goslar |
18
-
9
+ | NAME | Mortadella |
10
+ | TYPE | Ruby Gem |
@@ -1,16 +1,12 @@
1
1
  Feature: Verifying emptiness
2
2
 
3
- (see ../horizontal_tables/emptiness.feature)
4
-
5
-
6
3
  Scenario: an empty table
7
- Given I have a Mortadella instance: "m = Mortadella::Vertical.new"
8
- When I ask it whether it is empty: "m.empty?"
4
+ Given I have a Mortadella instance: "m = Mortadella::Vertical.new"
5
+ When I ask it whether it is empty: "m.empty?"
9
6
  Then it responds with true
10
7
 
11
-
12
8
  Scenario: a non-empty table
13
- Given I have a Mortadella instance: "m = Mortadella::Vertical.new"
14
- And I add a data row: "m['NAME'] = 'Mortadella'"
15
- When I ask it whether it is empty: "m.empty?"
9
+ Given I have a Mortadella instance: "m = Mortadella::Vertical.new"
10
+ And I add a data row: "m['NAME'] = 'Mortadella'"
11
+ When I ask it whether it is empty: "m.empty?"
16
12
  Then it responds with false
data/git-town.toml ADDED
@@ -0,0 +1,7 @@
1
+ # See https://www.git-town.com/configuration-file for details
2
+
3
+ [branches]
4
+ main = "main"
5
+
6
+ [sync]
7
+ feature-strategy = "rebase"
@@ -1,65 +1,97 @@
1
- module Mortadella
1
+ # frozen_string_literal: true
2
2
 
3
- # Makes it easy to build DRY horizontal Cucumber-compatible tables
3
+ module Mortadella
4
+ # Horizontal makes it easy to build horizontal Cucumber-compatible tables.
4
5
  class Horizontal
5
-
6
+ # @return [Array<Array<String>>] The resulting Cucumber-compatible table structure.
6
7
  attr_reader :table
7
8
 
8
-
9
- def initialize headers:, dry: []
9
+ # @param headers [Array<String>] The column headers for the table.
10
+ # @param dry [Array<String>] Column names for which repeated values can be removed.
11
+ # @return [void]
12
+ def initialize(headers:, dry: [])
10
13
  @headers = headers
11
-
12
14
  @dry = dry
13
15
 
14
- # The resulting Cucumber-compatible table structure
16
+ # The resulting Cucumber-compatible table structure.
15
17
  @table = [headers]
16
18
 
17
19
  # The previously added row
18
20
  @previous_row = nil
19
21
  end
20
22
 
21
-
22
- # Adds the given row to the table
23
- def << row
23
+ # Adds the given row to the table.
24
+ # @param row [Array<String>] The row data to add.
25
+ # @return [void]
26
+ def <<(row)
27
+ validate_row_length!(row)
24
28
  @table << dry_up(row)
25
29
  @previous_row = row
26
30
  end
27
31
 
28
-
32
+ # Indicates whether the table contains no data rows (only a header row).
33
+ # @return [Boolean]
29
34
  def empty?
30
35
  @table.size == 1
31
36
  end
32
37
 
38
+ # Filters the table to keep only the specified columns.
39
+ # @param columns [Array<String>] Names of the columns to keep.
40
+ # @return [void]
41
+ def keep_matching_columns(columns)
42
+ column_indices_to_drop(columns).sort.reverse_each do |column_index|
43
+ @table.each do |row|
44
+ row.delete_at column_index
45
+ end
46
+ end
47
+ end
33
48
 
49
+ private
34
50
 
35
- private
36
-
37
-
38
- # Returns whether the column with the given name can be dried up
39
- def can_dry? column_name
51
+ # Returns whether the column with the given name can be dried up.
52
+ # @param column_name [String]
53
+ # @return [Boolean]
54
+ def can_dry?(column_name)
40
55
  @dry.include? column_name
41
56
  end
42
57
 
58
+ # Returns the column indices to drop to make this table have the given columns.
59
+ # @param columns [Array<String>] The column names to keep.
60
+ # @return [Array<Integer>] Indices of columns to drop.
61
+ def column_indices_to_drop(columns)
62
+ result = []
63
+ headers = @table[0]
64
+ headers.each_with_index do |header, i|
65
+ result << i unless columns.include? header
66
+ end
67
+ result
68
+ end
43
69
 
44
- # Returns a dried up version of the given row
45
- # based on the row that came before in the table
46
- #
70
+ # Returns a dried up version of the given row based on the row that came before.
47
71
  # In a dried up row, any values that match the previous row are removed,
48
- # stopping on the first difference
49
- def dry_up row
50
- return row unless @previous_row
51
- row.clone.tap do |result|
52
- row.length.times do |i|
53
- if can_dry?(@headers[i]) && row[i] == @previous_row[i]
54
- result[i] = ''
55
- else
56
- break
57
- end
58
- end
72
+ # stopping on the first difference. Only columns marked as "dry" are affected.
73
+ # @param row [Array<String>] The row to dry up.
74
+ # @return [Array<String>] The dried up row.
75
+ def dry_up(row)
76
+ result = row.clone
77
+ return result unless @previous_row
78
+
79
+ result.length.times do |i|
80
+ break unless can_dry?(@headers[i]) && result[i] == @previous_row[i]
81
+
82
+ result[i] = ""
59
83
  end
84
+ result
60
85
  end
61
86
 
87
+ # Validates that the row has the correct number of elements.
88
+ # @param row [Array<String>] The row to validate.
89
+ # @return [void]
90
+ # @raise [ArgumentError] If the row length doesn't match the headers length.
91
+ def validate_row_length!(row)
92
+ return if row.length == @headers.length
62
93
 
94
+ raise ArgumentError, "Row length (#{row.length}) doesn't match headers (#{@headers.length})"
95
+ end
63
96
  end
64
-
65
97
  end
@@ -1,26 +1,41 @@
1
- module Mortadella
1
+ # frozen_string_literal: true
2
2
 
3
- # Makes it easy to build DRY vertical Cucumber-compatible tables
3
+ module Mortadella
4
+ # Vertical makes it easy to build vertical Cucumber-compatible tables.
5
+ # Vertical tables display data as key-value pairs, with headers in the first column
6
+ # and corresponding values in the second column.
4
7
  class Vertical
5
-
8
+ # @return [Array<Array<String>>] The Cucumber-compatible table.
6
9
  attr_reader :table
7
10
 
8
-
11
+ # Creates a new empty vertical table.
12
+ # @return [void]
9
13
  def initialize
10
14
  @table = []
11
15
  end
12
16
 
17
+ # Adds a new row to the table with the given header and value.
18
+ # @param header [String] The header (key) for the row.
19
+ # @param row [String] The data (value) for the given header.
20
+ # @return [void]
21
+ # @raise [ArgumentError] If header or row is nil.
22
+ def []=(header, row)
23
+ raise ArgumentError, "Header cannot be nil" if header.nil?
24
+ raise ArgumentError, "Row value cannot be nil" if row.nil?
13
25
 
14
- # Adds the given row to the table
15
- def []= header, row
16
26
  @table << [header, row]
17
27
  end
18
28
 
19
-
29
+ # Indicates whether the table contains no rows.
30
+ # @return [Boolean]
20
31
  def empty?
21
32
  @table.empty?
22
33
  end
23
34
 
35
+ # Converts the table to a hash.
36
+ # @return [Hash<String, String>] Hash representation of the table.
37
+ def to_h
38
+ @table.to_h
39
+ end
24
40
  end
25
-
26
41
  end
data/lib/mortadella.rb CHANGED
@@ -1,8 +1,22 @@
1
- require 'mortadella/horizontal'
2
- require 'mortadella/vertical'
1
+ # frozen_string_literal: true
3
2
 
3
+ require "mortadella/horizontal"
4
+ require "mortadella/vertical"
4
5
 
5
- #:nodoc:
6
+ # Mortadella makes it easy to programmatically build data tables for Cucumber testing.
7
+ #
8
+ # This module provides two main classes:
9
+ # - {Horizontal}: Build horizontal tables with column headers and data rows
10
+ # - {Vertical}: Build vertical tables with key-value pairs
11
+ #
12
+ # @example Using Horizontal tables
13
+ # table = Mortadella::Horizontal.new(headers: ['NAME', 'AGE'])
14
+ # table << ['Alice', '30']
15
+ # table << ['Bob', '25']
16
+ #
17
+ # @example Using Vertical tables
18
+ # table = Mortadella::Vertical.new
19
+ # table['NAME'] = 'Alice'
20
+ # table['AGE'] = '30'
6
21
  module Mortadella
7
-
8
22
  end
data/mortadella.gemspec CHANGED
@@ -1,25 +1,28 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
 
5
6
  Gem::Specification.new do |s|
6
- s.name = 'mortadella'
7
- s.version = '1.0.0'
8
- s.authors = ['Kevin Goslar']
9
- s.email = ['kevin.goslar@gmail.com']
10
- s.summary = %s(Mock Ruby Table Delivery)
11
- s.description = %s(A tool to create Ruby table object to be used for Cucumber comparisons)
12
- s.homepage = 'https://github.com/Originate/mortadella'
13
- s.license = 'MIT'
7
+ s.name = "mortadella"
8
+ s.version = "1.2.0"
9
+ s.authors = ["Kevin Goslar"]
10
+ s.email = ["kevin.goslar@gmail.com"]
11
+ s.summary = "Build Cucumber-compatible data tables programmatically"
12
+ s.description = "Mortadella makes it easy to programmatically build data tables for " \
13
+ "Cucumber testing. Supports both horizontal (row-based) and vertical " \
14
+ "(key-value) table formats with powerful features like column filtering " \
15
+ "and field deduplication."
16
+ s.homepage = "https://github.com/kevgo/mortadella-ruby"
17
+ s.license = "MIT"
14
18
 
15
19
  s.files = `git ls-files -z`.split("\x0")
16
- s.test_files = Dir['features/*']
17
- s.require_paths = ['lib']
20
+ s.require_paths = ["lib"]
21
+ s.required_ruby_version = ">= 2.7"
18
22
 
19
- s.add_development_dependency 'bundler'
20
- s.add_development_dependency 'coveralls'
21
- s.add_development_dependency 'cucumber'
22
- s.add_development_dependency 'rake'
23
- s.add_development_dependency 'rubocop'
24
- s.add_development_dependency 'rspec'
23
+ s.metadata["rubygems_mfa_required"] = "true"
24
+ s.metadata["homepage_uri"] = s.homepage
25
+ s.metadata["source_code_uri"] = "https://github.com/kevgo/mortadella-ruby"
26
+ s.metadata["changelog_uri"] = "https://github.com/kevgo/mortadella-ruby/blob/main/CHANGELOG.md"
27
+ s.metadata["bug_tracker_uri"] = "https://github.com/kevgo/mortadella-ruby/issues"
25
28
  end
metadata CHANGED
@@ -1,100 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mortadella
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Goslar
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2015-12-22 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: coveralls
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: cucumber
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: rake
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rubocop
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rspec
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- description: A tool to create Ruby table object to be used for Cucumber comparisons
10
+ date: 2025-11-04 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Mortadella makes it easy to programmatically build data tables for Cucumber
13
+ testing. Supports both horizontal (row-based) and vertical (key-value) table formats
14
+ with powerful features like column filtering and field deduplication.
98
15
  email:
99
16
  - kevin.goslar@gmail.com
100
17
  executables: []
@@ -102,31 +19,41 @@ extensions: []
102
19
  extra_rdoc_files: []
103
20
  files:
104
21
  - ".coveralls.yml"
22
+ - ".github/workflows/ruby.yml"
105
23
  - ".gitignore"
106
24
  - ".rubocop.yml"
107
- - ".ruby-version"
25
+ - CHANGELOG.md
26
+ - DEVELOPMENT.md
108
27
  - Gemfile
109
28
  - Gemfile.lock
110
29
  - LICENSE.txt
111
30
  - README.md
112
31
  - Rakefile
113
- - circle.yml
32
+ - cucumber.yml
33
+ - documentation/ingredients.png
34
+ - dprint.json
114
35
  - features/horizontal_tables/basic_usage.feature
115
36
  - features/horizontal_tables/drying_up_fields.feature
116
37
  - features/horizontal_tables/emptiness.feature
38
+ - features/horizontal_tables/keep_matching_columns.feature
117
39
  - features/step_definitions/steps.rb
118
40
  - features/support/env.rb
119
41
  - features/vertical_tables/basic_usage.feature
120
42
  - features/vertical_tables/emptiness.feature
43
+ - git-town.toml
121
44
  - lib/mortadella.rb
122
45
  - lib/mortadella/horizontal.rb
123
46
  - lib/mortadella/vertical.rb
124
47
  - mortadella.gemspec
125
- homepage: https://github.com/Originate/mortadella
48
+ homepage: https://github.com/kevgo/mortadella-ruby
126
49
  licenses:
127
50
  - MIT
128
- metadata: {}
129
- post_install_message:
51
+ metadata:
52
+ rubygems_mfa_required: 'true'
53
+ homepage_uri: https://github.com/kevgo/mortadella-ruby
54
+ source_code_uri: https://github.com/kevgo/mortadella-ruby
55
+ changelog_uri: https://github.com/kevgo/mortadella-ruby/blob/main/CHANGELOG.md
56
+ bug_tracker_uri: https://github.com/kevgo/mortadella-ruby/issues
130
57
  rdoc_options: []
131
58
  require_paths:
132
59
  - lib
@@ -134,16 +61,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
61
  requirements:
135
62
  - - ">="
136
63
  - !ruby/object:Gem::Version
137
- version: '0'
64
+ version: '2.7'
138
65
  required_rubygems_version: !ruby/object:Gem::Requirement
139
66
  requirements:
140
67
  - - ">="
141
68
  - !ruby/object:Gem::Version
142
69
  version: '0'
143
70
  requirements: []
144
- rubyforge_project:
145
- rubygems_version: 2.4.5.1
146
- signing_key:
71
+ rubygems_version: 3.6.2
147
72
  specification_version: 4
148
- summary: Mock Ruby Table Delivery
73
+ summary: Build Cucumber-compatible data tables programmatically
149
74
  test_files: []
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 2.2.3
data/circle.yml DELETED
@@ -1,4 +0,0 @@
1
- test:
2
- override:
3
- - bundle exec rake
4
-