joined 0.3.0 → 0.4.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
2
  SHA256:
3
- metadata.gz: bf39163ca7677fe7c82b64f86a58ed1960ab37ff099a3d3530a98604d0db8d2f
4
- data.tar.gz: cac313f36a472d3543f1f61b0d23e428484ebf26dcdf78a8ee8e7001527a17ce
3
+ metadata.gz: 563c180d4891dc838b3533637125a06c64d93a90798d9b0e1f2bd76cd0f0a801
4
+ data.tar.gz: 5aa15275318d58c1c15fa774d1e6fe27580bcf91780fd11bf1707664d38172cc
5
5
  SHA512:
6
- metadata.gz: 17ac3bfd0677cde3c1caf8e49b52c24addeaa3512053e6aa60b21a36b9c574b67df9834bdd5068159c78186bc3c3ab40b87d02cb7d9e6ff1074492bf3bbdf047
7
- data.tar.gz: 978bbf113d2e52aa15dfc935c219dc2cca47fdc0cea9f84671f6083bc472b193c8085ea4251a0f58a79027c3348d26e23734ff725cfce799c0cdb712f77779ae
6
+ metadata.gz: e680539a587552928133111eec3f77cf76aa5eea4584084417a4945dd39d062187533e77bf996cabf67d3d4da0df0d8fda10ec04ae65bbf2e9b901e80dc522b4
7
+ data.tar.gz: 2a685f9a47ec5f7474d4c36a2cb3bf97c1afe8a4373e6b93a86b0a8354ab829834848b112e9c8b69d344c4e9c9158afa6e85e6b6e9d3abab0f138ef81ca4cd91
@@ -16,4 +16,4 @@ jobs:
16
16
  runs-on: ubuntu-24.04
17
17
  steps:
18
18
  - uses: actions/checkout@v4
19
- - uses: yegor256/copyrights-action@0.0.8
19
+ - uses: yegor256/copyrights-action@0.0.12
@@ -16,4 +16,4 @@ jobs:
16
16
  runs-on: ubuntu-24.04
17
17
  steps:
18
18
  - uses: actions/checkout@v4
19
- - uses: crate-ci/typos@v1.32.0
19
+ - uses: crate-ci/typos@v1.34.0
data/.gitignore CHANGED
@@ -1,9 +1,10 @@
1
+ *.gem
1
2
  .bundle/
3
+ .claude/
2
4
  .DS_Store
3
5
  .idea/
4
- .yardoc/
5
- *.gem
6
6
  .ruby-*
7
+ .yardoc/
7
8
  coverage/
8
9
  doc/
9
10
  node_modules/
data/.mdl_style.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ all
7
+ # see rule documentation and defaults: https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md
8
+ # e.g. to override line length check:
9
+ # rule 'MD013', line_length: 60
data/.mdlrc ADDED
@@ -0,0 +1,4 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ style '.mdl_style.rb'
data/.rubocop.yml CHANGED
@@ -18,4 +18,17 @@ Layout/EndOfLine:
18
18
  EnforcedStyle: lf
19
19
  Style/EvalWithLocation:
20
20
  Enabled: false
21
- require: []
21
+ Metrics/MethodLength:
22
+ Enabled: false
23
+ Metrics/CyclomaticComplexity:
24
+ Enabled: false
25
+ Metrics/AbcSize:
26
+ Enabled: false
27
+ Metrics/PerceivedComplexity:
28
+ Enabled: false
29
+ Minitest/EmptyLineBeforeAssertionMethods:
30
+ Enabled: false
31
+ Layout/EmptyLineAfterGuardClause:
32
+ Enabled: false
33
+ Metrics/ParameterLists:
34
+ Enabled: false
data/Gemfile CHANGED
@@ -6,14 +6,14 @@
6
6
  source 'https://rubygems.org'
7
7
  gemspec
8
8
 
9
+ gem 'mdl', '~>0.13', require: false
9
10
  gem 'minitest', '~>5.25', require: false
10
11
  gem 'minitest-reporters', '~>1.7', require: false
11
12
  gem 'rake', '~>13.2', require: false
12
13
  gem 'rubocop', '~>1.64', require: false
13
- gem 'rubocop-minitest', '>0', require: false
14
- gem 'rubocop-performance', '>0', require: false
15
- gem 'rubocop-rake', '>0', require: false
16
- gem 'rubocop-rspec', '>0', require: false
14
+ gem 'rubocop-minitest', '~>0.38', require: false
15
+ gem 'rubocop-performance', '~>1.25', require: false
16
+ gem 'rubocop-rake', '~>0.7', require: false
17
17
  gem 'simplecov', '~>0.22', require: false
18
18
  gem 'simplecov-cobertura', '~>2.1', require: false
19
19
  gem 'yard', '~>0.9', require: false
data/Gemfile.lock CHANGED
@@ -9,16 +9,42 @@ GEM
9
9
  ansi (1.5.0)
10
10
  ast (2.4.3)
11
11
  builder (3.3.0)
12
+ chef-utils (18.7.10)
13
+ concurrent-ruby
14
+ concurrent-ruby (1.3.5)
12
15
  docile (1.4.1)
13
- json (2.12.0)
16
+ ffi (1.17.2-x64-mingw-ucrt)
17
+ ffi-win32-extensions (1.0.4)
18
+ ffi
19
+ json (2.12.2)
20
+ kramdown (2.5.1)
21
+ rexml (>= 3.3.9)
22
+ kramdown-parser-gfm (1.1.0)
23
+ kramdown (~> 2.0)
14
24
  language_server-protocol (3.17.0.5)
15
25
  lint_roller (1.1.0)
26
+ mdl (0.13.0)
27
+ kramdown (~> 2.3)
28
+ kramdown-parser-gfm (~> 1.1)
29
+ mixlib-cli (~> 2.1, >= 2.1.1)
30
+ mixlib-config (>= 2.2.1, < 4)
31
+ mixlib-shellout
16
32
  minitest (5.25.5)
17
33
  minitest-reporters (1.7.1)
18
34
  ansi
19
35
  builder
20
36
  minitest (>= 5.0)
21
37
  ruby-progressbar
38
+ mixlib-cli (2.1.8)
39
+ mixlib-config (3.0.27)
40
+ tomlrb
41
+ mixlib-shellout (3.3.9)
42
+ chef-utils
43
+ mixlib-shellout (3.3.9-x64-mingw-ucrt)
44
+ chef-utils
45
+ ffi-win32-extensions (~> 1.0.3)
46
+ win32-process (~> 0.9)
47
+ wmi-lite (~> 1.0)
22
48
  parallel (1.27.0)
23
49
  parser (3.3.8.0)
24
50
  ast (~> 2.4.1)
@@ -26,10 +52,10 @@ GEM
26
52
  prism (1.4.0)
27
53
  racc (1.8.1)
28
54
  rainbow (3.1.1)
29
- rake (13.2.1)
55
+ rake (13.3.0)
30
56
  regexp_parser (2.10.0)
31
57
  rexml (3.4.1)
32
- rubocop (1.75.6)
58
+ rubocop (1.77.0)
33
59
  json (~> 2.3)
34
60
  language_server-protocol (~> 3.17.0.2)
35
61
  lint_roller (~> 1.1.0)
@@ -37,13 +63,13 @@ GEM
37
63
  parser (>= 3.3.0.2)
38
64
  rainbow (>= 2.2.2, < 4.0)
39
65
  regexp_parser (>= 2.9.3, < 3.0)
40
- rubocop-ast (>= 1.44.0, < 2.0)
66
+ rubocop-ast (>= 1.45.1, < 2.0)
41
67
  ruby-progressbar (~> 1.7)
42
68
  unicode-display_width (>= 2.4.0, < 4.0)
43
- rubocop-ast (1.44.1)
69
+ rubocop-ast (1.45.1)
44
70
  parser (>= 3.3.7.2)
45
71
  prism (~> 1.4)
46
- rubocop-minitest (0.38.0)
72
+ rubocop-minitest (0.38.1)
47
73
  lint_roller (~> 1.1)
48
74
  rubocop (>= 1.75.0, < 2.0)
49
75
  rubocop-ast (>= 1.38.0, < 2.0)
@@ -54,9 +80,6 @@ GEM
54
80
  rubocop-rake (0.7.1)
55
81
  lint_roller (~> 1.1)
56
82
  rubocop (>= 1.72.1)
57
- rubocop-rspec (3.6.0)
58
- lint_roller (~> 1.1)
59
- rubocop (~> 1.72, >= 1.72.1)
60
83
  ruby-progressbar (1.13.0)
61
84
  simplecov (0.22.0)
62
85
  docile (~> 1.1)
@@ -67,9 +90,13 @@ GEM
67
90
  simplecov (~> 0.19)
68
91
  simplecov-html (0.13.1)
69
92
  simplecov_json_formatter (0.1.4)
93
+ tomlrb (2.0.3)
70
94
  unicode-display_width (3.1.4)
71
95
  unicode-emoji (~> 4.0, >= 4.0.4)
72
96
  unicode-emoji (4.0.4)
97
+ win32-process (0.10.0)
98
+ ffi (>= 1.0.0)
99
+ wmi-lite (1.0.7)
73
100
  yard (0.9.37)
74
101
 
75
102
  PLATFORMS
@@ -84,14 +111,14 @@ PLATFORMS
84
111
 
85
112
  DEPENDENCIES
86
113
  joined!
114
+ mdl (~> 0.13)
87
115
  minitest (~> 5.25)
88
116
  minitest-reporters (~> 1.7)
89
117
  rake (~> 13.2)
90
118
  rubocop (~> 1.64)
91
- rubocop-minitest (> 0)
92
- rubocop-performance (> 0)
93
- rubocop-rake (> 0)
94
- rubocop-rspec (> 0)
119
+ rubocop-minitest (~> 0.38)
120
+ rubocop-performance (~> 1.25)
121
+ rubocop-rake (~> 0.7)
95
122
  simplecov (~> 0.22)
96
123
  simplecov-cobertura (~> 2.1)
97
124
  yard (~> 0.9)
data/README.md CHANGED
@@ -25,22 +25,41 @@ Prints:
25
25
  orange, banana, and pear
26
26
  ```
27
27
 
28
+ You can also limit the number of displayed elements:
29
+
30
+ ```ruby
31
+ require 'joined'
32
+ puts ['apple', 'orange', 'banana', 'pear', 'grape'].joined(max: 3)
33
+ ```
34
+
35
+ Prints:
36
+
37
+ ```text
38
+ apple, orange, banana, etc.
39
+ ```
40
+
28
41
  That's it.
29
42
 
30
43
  ## Options
31
44
 
32
45
  The `joined` method supports the following parameters:
33
46
 
34
- * `words_connector` (String) (defaults to: ', ') -
47
+ * `words_connector` (String) (defaults to: `", "`) -
35
48
  the string used to join all but the last element of the list.
36
- * `last_word_connector` (String) (defaults to: ', and ') -
49
+ * `last_word_connector` (String) (defaults to: `", and "`) -
37
50
  the string used to join the last element of the list.
38
- * `oxford` (Boolean) (defaults to: true) -
51
+ * `oxford` (Boolean) (defaults to: `true`) -
39
52
  should we place a comma before the `last_word_connector`?
40
53
  If false, it will remove a leading comma from the `last_word_connector`.
41
54
  If true, it will preserve the leading comma specified
42
55
  in the `last_word_connector`, but it will not insert one
43
56
  if not already present.
57
+ * `comma_before` (Boolean) (defaults to: `false`) -
58
+ If true, adds the comma inside quotation marks (e.g. `"one," "two," and "three"`).
59
+ If false, adds the comma outside quotation marks (e.g. `"one", "two", and "three"`).
60
+ * `max` (Integer) (defaults to: `nil`) -
61
+ Maximum number of elements to show. If the array has more elements than this value,
62
+ only the first `max` elements will be displayed, followed by ", etc.".
44
63
 
45
64
  See the
46
65
  [Yard docs](https://rubydoc.info/github/yegor256/joined/master/frames)
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ def version
15
15
  Gem::Specification.load(Dir['*.gemspec'].first).version
16
16
  end
17
17
 
18
- task default: %i[clean test rubocop yard]
18
+ task default: %i[clean test rubocop mdl yard]
19
19
 
20
20
  require 'rake/testtask'
21
21
  desc 'Run all unit tests'
@@ -38,3 +38,8 @@ desc 'Run RuboCop on all directories'
38
38
  RuboCop::RakeTask.new(:rubocop) do |task|
39
39
  task.fail_on_error = true
40
40
  end
41
+
42
+ desc 'Run MarkdownLint (mdl) on all Markdown files'
43
+ task :mdl do
44
+ sh 'mdl README.md'
45
+ end
data/joined.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
10
10
  s.required_ruby_version = '>=3.2'
11
11
  s.name = 'joined'
12
- s.version = '0.3.0'
12
+ s.version = '0.4.0'
13
13
  s.license = 'MIT'
14
14
  s.summary = 'A simple Ruby gem that adds a .joined() method to Array'
15
15
  s.description =
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  'separating them with commas and placing "and" before the last element.'
19
19
  s.authors = ['Yegor Bugayenko']
20
20
  s.email = 'yegor256@gmail.com'
21
- s.homepage = 'http://github.com/yegor256/joined'
21
+ s.homepage = 'https://github.com/yegor256/joined'
22
22
  s.files = `git ls-files`.split($RS)
23
23
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
24
  s.rdoc_options = ['--charset=UTF-8']
data/lib/joined.rb CHANGED
@@ -24,19 +24,38 @@ class Array
24
24
  # if not already present.
25
25
  # @param [Boolean] comma_before
26
26
  # Should we move comma before the quotes symbol
27
- # If false, it will do nothing
28
- # If true, it will move all commas before the quotes
27
+ # If false, adds the comma outside quotation marks
28
+ # If true, adds the comma inside quotation marks
29
+ # @param [Integer] max
30
+ # Maximum number of elements to show. If array has more elements,
31
+ # append the etc suffix to the result.
32
+ # @param [String] etc
33
+ # The suffix to append when max is specified and array is truncated.
29
34
  # @return [String] The text generated (with items joined)
30
- def joined(oxford: true, words_connector: ', ', last_word_connector: ', and ', comma_before: false)
35
+ def joined(oxford: true, words_connector: ', ', last_word_connector: ', and ',
36
+ comma_before: false, max: nil, etc: ', etc.')
31
37
  return '' if empty?
32
- return first if length == 1
33
-
34
- final_connector = (last_word_connector || '').dup
35
- final_connector.sub!(/^,/, '') unless oxford && length > 2
36
-
37
- result = "#{self[0...-1].join(words_connector)}#{final_connector}#{self[-1]}"
38
- return result.gsub(/"([^"]+)"\s*,/, '"\1,"') if comma_before
39
-
38
+ return etc if max&.zero?
39
+ array = self
40
+ truncated = false
41
+ if max && length > max
42
+ array = self[0...max]
43
+ truncated = true
44
+ end
45
+ if array.length == 1
46
+ result = array.first
47
+ result += etc if truncated
48
+ return result
49
+ end
50
+ if truncated
51
+ result = array.join(words_connector)
52
+ else
53
+ final = (last_word_connector || '').dup
54
+ final.sub!(/^,/, '') unless oxford && array.length > 2
55
+ result = "#{array[0...-1].join(words_connector)}#{final}#{array[-1]}"
56
+ end
57
+ result.gsub!(/"([^"]+)"\s*,/, '"\1,"') if comma_before
58
+ result += etc if truncated
40
59
  result
41
60
  end
42
61
  end
data/test/test_joined.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
+ require_relative 'test__helper'
6
7
  require_relative '../lib/joined'
7
8
 
8
9
  # Test.
@@ -65,7 +66,25 @@ class Testjoined < Minitest::Test
65
66
  assert_equal 'unknown keyword: :passing', exception.message
66
67
  end
67
68
 
68
- def test_with_comma_before
69
- assert_equal '"one," "two," and "three"', %w[one two three].map { |f| "\"#{f}\"" }.joined(comma_before: true)
69
+ def test_quoted_items_with_comma_before
70
+ list = ['"one"', '"two"', '"three"']
71
+ assert_equal '"one," "two," and "three"', list.joined(comma_before: true)
72
+ assert_equal '"one", "two", and "three"', list.joined(comma_before: false)
73
+ assert_equal '"one", "two", and "three"', list.joined
74
+ assert_equal '"one," "two" and "three"', list.joined(comma_before: true, oxford: false)
75
+ assert_equal '"one", "two" and "three"', list.joined(comma_before: false, oxford: false)
76
+ assert_equal '"one", "two" and "three"', list.joined(oxford: false)
77
+ end
78
+
79
+ def test_comma_before_only_handles_trailing_quotes
80
+ list = ['"one"-fer', '"two"', '"three"']
81
+ assert_equal '"one"-fer, "two," and "three"', list.joined(comma_before: true)
82
+ assert_equal '"one"-fer, "two", and "three"', list.joined(comma_before: false)
83
+ end
84
+
85
+ def test_comma_before_collapses_trailing_whitespace
86
+ list = ['"one" ', '"two" ', '"three" ']
87
+ assert_equal '"one," "two," and "three" ', list.joined(comma_before: true)
88
+ assert_equal '"one" , "two" , and "three" ', list.joined(comma_before: false)
70
89
  end
71
90
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative 'test__helper'
7
+ require_relative '../lib/joined'
8
+
9
+ # Test for max parameter.
10
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
11
+ # Copyright:: Copyright (c) 2025 Yegor Bugayenko
12
+ # License:: MIT
13
+ class TestjoinedMax < Minitest::Test
14
+ def test_with_max_parameter_when_array_has_more_elements
15
+ assert_equal 'one, two, three, four, etc.', %w[one two three four five six].joined(max: 4)
16
+ end
17
+
18
+ def test_with_max_parameter_when_array_has_exact_elements
19
+ assert_equal 'one, two, three, and four', %w[one two three four].joined(max: 4)
20
+ end
21
+
22
+ def test_with_max_parameter_when_array_has_fewer_elements
23
+ assert_equal 'one, two, and three', %w[one two three].joined(max: 4)
24
+ end
25
+
26
+ def test_with_max_parameter_and_two_elements
27
+ assert_equal 'one and two', %w[one two].joined(max: 4)
28
+ end
29
+
30
+ def test_with_max_parameter_and_one_element
31
+ assert_equal 'one', %w[one].joined(max: 4)
32
+ end
33
+
34
+ def test_with_max_parameter_and_empty_array
35
+ assert_equal '', [].joined(max: 4)
36
+ end
37
+
38
+ def test_with_max_equals_one_and_multiple_elements
39
+ assert_equal 'one, etc.', %w[one two three four].joined(max: 1)
40
+ end
41
+
42
+ def test_with_max_equals_two_and_multiple_elements
43
+ assert_equal 'one, two, etc.', %w[one two three four].joined(max: 2)
44
+ end
45
+
46
+ def test_with_max_equals_three_and_multiple_elements
47
+ assert_equal 'one, two, three, etc.', %w[one two three four five].joined(max: 3)
48
+ end
49
+
50
+ def test_max_with_oxford_false
51
+ assert_equal 'one, two, three, four, etc.', %w[one two three four five six].joined(max: 4, oxford: false)
52
+ end
53
+
54
+ def test_max_with_custom_connectors
55
+ result = %w[one two three four five].joined(max: 4, words_connector: '; ',
56
+ last_word_connector: '; and also ')
57
+ assert_equal 'one; two; three; four, etc.', result
58
+ end
59
+
60
+ def test_max_with_comma_before_and_quoted_items
61
+ list = ['"one"', '"two"', '"three"', '"four"', '"five"']
62
+ assert_equal '"one," "two," "three," "four", etc.', list.joined(max: 4, comma_before: true)
63
+ end
64
+
65
+ def test_max_with_nil_value_behaves_like_no_max
66
+ assert_equal 'one, two, three, four, and five', %w[one two three four five].joined(max: nil)
67
+ end
68
+
69
+ def test_max_with_zero_returns_empty_string
70
+ assert_equal ', etc.', %w[one two three].joined(max: 0)
71
+ end
72
+
73
+ def test_max_with_very_large_array
74
+ array = (1..100).map(&:to_s)
75
+ result = array.joined(max: 5)
76
+ assert_equal '1, 2, 3, 4, 5, etc.', result
77
+ end
78
+
79
+ def test_max_with_unicode_elements
80
+ array = %w[α β γ δ ε ζ]
81
+ assert_equal 'α, β, γ, δ, etc.', array.joined(max: 4)
82
+ end
83
+
84
+ def test_max_with_special_characters
85
+ array = ['foo!', 'bar?', 'baz&', 'qux*', 'quux#']
86
+ assert_equal 'foo!, bar?, baz&, etc.', array.joined(max: 3)
87
+ end
88
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: joined
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -25,7 +25,6 @@ files:
25
25
  - ".github/workflows/codecov.yml"
26
26
  - ".github/workflows/copyrights.yml"
27
27
  - ".github/workflows/license.yml"
28
- - ".github/workflows/markdown-lint.yml"
29
28
  - ".github/workflows/pdd.yml"
30
29
  - ".github/workflows/rake.yml"
31
30
  - ".github/workflows/reuse.yml"
@@ -33,6 +32,8 @@ files:
33
32
  - ".github/workflows/xcop.yml"
34
33
  - ".github/workflows/yamllint.yml"
35
34
  - ".gitignore"
35
+ - ".mdl_style.rb"
36
+ - ".mdlrc"
36
37
  - ".pdd"
37
38
  - ".rubocop.yml"
38
39
  - ".rultor.yml"
@@ -48,7 +49,8 @@ files:
48
49
  - renovate.json
49
50
  - test/test__helper.rb
50
51
  - test/test_joined.rb
51
- homepage: http://github.com/yegor256/joined
52
+ - test/test_joined_max.rb
53
+ homepage: https://github.com/yegor256/joined
52
54
  licenses:
53
55
  - MIT
54
56
  metadata:
@@ -1,23 +0,0 @@
1
- # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
2
- # SPDX-License-Identifier: MIT
3
- ---
4
- # yamllint disable rule:line-length
5
- name: markdown-lint
6
- 'on':
7
- push:
8
- branches:
9
- - master
10
- pull_request:
11
- branches:
12
- - master
13
- paths-ignore: ['paper/**', 'sandbox/**']
14
- concurrency:
15
- group: markdown-lint-${{ github.ref }}
16
- cancel-in-progress: true
17
- jobs:
18
- markdown-lint:
19
- timeout-minutes: 15
20
- runs-on: ubuntu-24.04
21
- steps:
22
- - uses: actions/checkout@v4
23
- - uses: articulate/actions-markdownlint@v1