character_set 1.5.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -1
  3. data/.github/workflows/tests.yml +6 -2
  4. data/BENCHMARK.md +35 -31
  5. data/CHANGELOG.md +30 -1
  6. data/Gemfile +14 -0
  7. data/README.md +9 -6
  8. data/Rakefile +2 -120
  9. data/character_set.gemspec +0 -21
  10. data/ext/character_set/character_set.c +110 -125
  11. data/lib/character_set/core_ext/string_ext.rb +1 -1
  12. data/lib/character_set/parser.rb +8 -4
  13. data/lib/character_set/predefined_sets/assigned.cps +73 -52
  14. data/lib/character_set/predefined_sets/emoji.cps +10 -9
  15. data/lib/character_set/predefined_sets.rb +11 -0
  16. data/lib/character_set/ruby_fallback/character_set_methods.rb +17 -20
  17. data/lib/character_set/ruby_fallback/set_methods.rb +4 -18
  18. data/lib/character_set/ruby_fallback/vendored_set_classes.rb +492 -0
  19. data/lib/character_set/ruby_fallback.rb +2 -6
  20. data/lib/character_set/shared_methods.rb +8 -2
  21. data/lib/character_set/version.rb +1 -1
  22. data/tasks/benchmark.rake +20 -0
  23. data/{benchmarks → tasks/benchmarks}/delete_in.rb +5 -1
  24. data/{benchmarks → tasks/benchmarks}/keep_in.rb +5 -1
  25. data/tasks/benchmarks/shared.rb +28 -0
  26. data/tasks/sync_casefold_data.rake +20 -0
  27. data/tasks/sync_predefined_sets.rake +9 -0
  28. data/tasks/sync_ruby_spec.rake +65 -0
  29. metadata +20 -183
  30. data/benchmarks/shared.rb +0 -30
  31. /data/{benchmarks → tasks/benchmarks}/count_in.rb +0 -0
  32. /data/{benchmarks → tasks/benchmarks}/cover.rb +0 -0
  33. /data/{benchmarks → tasks/benchmarks}/scan.rb +0 -0
  34. /data/{benchmarks → tasks/benchmarks}/used_by.rb +0 -0
  35. /data/{benchmarks → tasks/benchmarks}/z_add.rb +0 -0
  36. /data/{benchmarks → tasks/benchmarks}/z_delete.rb +0 -0
  37. /data/{benchmarks → tasks/benchmarks}/z_merge.rb +0 -0
  38. /data/{benchmarks → tasks/benchmarks}/z_minmax.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9622bc20bbdb48f8deff84dbed9e800e6bc500a6a08a27e7b3aea2ea651cd278
4
- data.tar.gz: 5853e8d5be7e9a1963419aa4f9fbc631148fe5bef45aa185b9117d32b44aa959
3
+ metadata.gz: 778cea0208adb290e09f454e3f88c021531decede99604cf2b67f48c9ab3bcd8
4
+ data.tar.gz: 43672f0afce2846bec846791e7445c9614605194967e061b1d9f0be305298be4
5
5
  SHA512:
6
- metadata.gz: 2cc2a60b9388a2e3beef66da20aa8205cc501980a7dc66f2716c66f7e999a083927b27a761e6b932b6d5c16b8e5968f8e04370ecf3c999326f378f60bfa3cedc
7
- data.tar.gz: a2a8d1f9ac6cdf6302af98662fc3efda4b8c6fe003c7cdc853a61a64f9c7a596b1bbd7a79dca19081b8ce2576f9c3d848869141b164c145e22befaaffec8b265
6
+ metadata.gz: 635f9fb21c973b03b9a0556f2b6cf2c608753acb73616aa8681a5bada3418f955ec887164a03fd2add4edae8a60292eb6e4b681d11a8cf33d1083499afe83815
7
+ data.tar.gz: 6a80f4f7f3f6c2357d84dc71bb5086f273471a8ae5af4e09abc502dc9893da90962d49527b40564de664af0a910f2e99720062dd41ba53427882ecb36e1a40a0
data/.gitattributes CHANGED
@@ -1,3 +1,3 @@
1
1
  *.cps linguist-detectable=false
2
2
  benchmarks/* linguist-detectable=false
3
- spec/ruby-spec/* linguist-vendored
3
+ spec/* linguist-detectable=false
@@ -1,6 +1,10 @@
1
1
  name: tests
2
2
 
3
- on: [push, pull_request]
3
+ on:
4
+ push:
5
+ pull_request:
6
+ schedule:
7
+ - cron: '11 11 14 * *' # at 11:11 am on the 14th of every month
4
8
 
5
9
  jobs:
6
10
  build:
@@ -8,7 +12,7 @@ jobs:
8
12
 
9
13
  strategy:
10
14
  matrix:
11
- ruby: [ '2.2', '2.7', '3.0', 'ruby-head', 'jruby-head' ]
15
+ ruby: [ '2.2', '2.7', '3.0', '3.1', 'ruby-head', 'jruby-head' ]
12
16
 
13
17
  steps:
14
18
  - uses: actions/checkout@v2
data/BENCHMARK.md CHANGED
@@ -1,86 +1,90 @@
1
- Results of `rake:benchmark` on ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
1
+ Results of `rake:benchmark` on ruby 3.2.0dev (2022-02-14T14:35:54Z master 26187a8520) [arm64-darwin21]
2
2
 
3
3
  ```
4
4
  Counting non-letters
5
5
 
6
- CharacterSet#count_in: 9472902.2 i/s
7
- String#count: 2221799.9 i/s - 4.26x slower
6
+ CharacterSet#count_in: 14627506.2 i/s
7
+ String#count: 3859777.0 i/s - 3.79x slower
8
8
  ```
9
9
  ```
10
10
  Detecting non-whitespace
11
11
 
12
- CharacterSet#cover?: 12388427.2 i/s
13
- Regexp#match?: 7901676.8 i/s - 1.57x slower
12
+ CharacterSet#cover?: 17241902.8 i/s
13
+ Regexp#match?: 12971122.6 i/s - 1.33x slower
14
14
  ```
15
15
  ```
16
16
  Detecting non-letters
17
17
 
18
- CharacterSet#cover?: 12263689.1 i/s
19
- Regexp#match?: 4940889.9 i/s - 2.48x slower
18
+ CharacterSet#cover?: 17243472.3 i/s
19
+ Regexp#match?: 7957626.9 i/s - 2.17x slower
20
20
  ```
21
21
  ```
22
- Removing whitespace
22
+ Removing ASCII whitespace
23
23
 
24
- CharacterSet#delete_in: 2406722.6 i/s
25
- String#gsub: 235760.3 i/s - 10.21x slower
24
+ CharacterSet#delete_in: 6190975.7 i/s
25
+ String#tr: 4722716.6 i/s - 1.31x slower
26
+ String#gsub: 214239.5 i/s - 28.90x slower
26
27
  ```
27
28
  ```
28
29
  Removing whitespace, emoji and umlauts
29
30
 
30
- CharacterSet#delete_in: 1653607.6 i/s
31
- String#gsub: 272782.9 i/s - 6.06x slower
31
+ CharacterSet#delete_in: 5890471.8 i/s
32
+ String#tr: 348506.8 i/s - 16.90x slower
33
+ String#gsub: 318268.3 i/s - 18.51x slower
32
34
  ```
33
35
  ```
34
36
  Removing non-whitespace
35
37
 
36
- CharacterSet#keep_in: 2671038.2 i/s
37
- String#gsub: 242551.0 i/s - 11.01x slower
38
+ CharacterSet#keep_in: 7396898.0 i/s
39
+ String#gsub: 208809.7 i/s - 35.42x slower
40
+ String#tr: 13.1 i/s - 564682.50x slower
38
41
  ```
39
42
  ```
40
- Extracting emoji
43
+ Keeping only emoji
41
44
 
42
- CharacterSet#keep_in: 1726496.5 i/s
43
- String#gsub: 215609.2 i/s - 8.01x slower
45
+ CharacterSet#keep_in: 7022741.1 i/s
46
+ String#gsub: 180939.6 i/s - 38.81x slower
47
+ String#tr: 13.1 i/s - 536724.50x slower
44
48
  ```
45
49
  ```
46
50
  Extracting emoji to an Array
47
51
 
48
- CharacterSet#scan: 2373856.1 i/s
49
- String#scan: 480000.5 i/s - 4.95x slower
52
+ CharacterSet#scan: 3023176.8 i/s
53
+ String#scan: 893225.8 i/s - 3.38x slower
50
54
  ```
51
55
  ```
52
56
  Detecting whitespace
53
57
 
54
- CharacterSet#used_by?: 11988328.7 i/s
55
- Regexp#match?: 6758146.8 i/s - 1.77x slower
58
+ CharacterSet#used_by?: 17284025.9 i/s
59
+ Regexp#match?: 11847064.5 i/s - 1.46x slower
56
60
  ```
57
61
  ```
58
62
  Detecting emoji in a large string
59
63
 
60
- CharacterSet#used_by?: 288223.3 i/s
61
- Regexp#match?: 102384.2 i/s - 2.82x slower
64
+ CharacterSet#used_by?: 341386.1 i/s
65
+ Regexp#match?: 183121.6 i/s - 1.86x slower
62
66
  ```
63
67
  ```
64
68
  Adding entries
65
69
 
66
- CharacterSet#add: 2538251.2 i/s
67
- SortedSet#add: 443925.9 i/s - 5.72x slower
70
+ CharacterSet#add: 4989762.3 i/s
71
+ SortedSet#add: 1157911.7 i/s - 4.31x slower
68
72
  ```
69
73
  ```
70
74
  Removing entries
71
75
 
72
- CharacterSet#delete: 2487620.8 i/s
73
- SortedSet#delete: 628816.1 i/s - 3.96x slower
76
+ CharacterSet#delete: 4996703.6 i/s
77
+ SortedSet#delete: 4177401.5 i/s - same-ish
74
78
  ```
75
79
  ```
76
80
  Merging entries
77
81
 
78
- CharacterSet#merge: 551.6 i/s
79
- SortedSet#merge: 1.4 i/s - 393.59x slower
82
+ CharacterSet#merge: 666.7 i/s
83
+ SortedSet#merge: 4.0 i/s - 167.84x slower
80
84
  ```
81
85
  ```
82
86
  Getting the min and max
83
87
 
84
- CharacterSet#minmax: 636890.7 i/s
85
- SortedSet#minmax: 254.1 i/s - 2506.20x slower
88
+ CharacterSet#minmax: 1596470.9 i/s
89
+ SortedSet#minmax: 866.4 i/s - 1842.74x slower
86
90
  ```
data/CHANGELOG.md CHANGED
@@ -4,6 +4,35 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [1.7.0] - 2023-05-12
10
+
11
+ ### Added
12
+
13
+ - new codepoints for `::assigned` and `::emoji` predefined sets, as in Ruby 3.2.0
14
+
15
+ ### Fixed
16
+
17
+ - fixed processing of Strings that are not ASCII- or UTF8-encoded
18
+ - removed dependency on `set` and `sorted_set`
19
+ - thanks to https://github.com/mikebaldry for reporting a related issue (#2)
20
+
21
+ ## [1.6.0] - 2022-02-16
22
+
23
+ ### Added
24
+
25
+ - `::of` now supports both `String` and `Regexp` arguments
26
+
27
+ ### Fixed
28
+
29
+ - fixed segfault during `String` manipulation on Ruby 3.2.0-dev
30
+ - improved performance for `String` manipulation
31
+ - allow usage in Ractors
32
+ - predefined sets must be pre-initialized for this, though
33
+ - e.g. `CharacterSet.ascii`, `keep_character_set(:ascii)` etc.
34
+ - call them once in the main Ractor to trigger initialization
35
+
7
36
  ## [1.5.0] - 2021-12-05
8
37
 
9
38
  ### Added
@@ -48,7 +77,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
48
77
  - reduced memory consumption by > 90% for most use cases via dynamic resizing
49
78
  - before, every set instance required 136 KB for codepoints
50
79
  - now, 16 bytes for a CharacterSet in ASCII space, 8 KB for one in BMP space etc.
51
- - `#count_in` and `#scan_in` methods for `String` interaction
80
+ - `#count_in` and `#scan` methods for `String` interaction
52
81
  - new predefined sets `::any`/`::all`, `::assigned`, `::surrogate`
53
82
  - conversion methods `#assigned_part`, `#valid_part`
54
83
  - sectioning methods `#ascii_part`, `#plane(n)`
data/Gemfile CHANGED
@@ -4,3 +4,17 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in character_set.gemspec
6
6
  gemspec
7
+
8
+ gem 'benchmark-ips', '~> 2.7'
9
+ gem 'get_process_mem', '~> 0.2.3'
10
+ gem 'rake', '~> 13.0'
11
+ gem 'rake-compiler', '~> 1.1'
12
+ gem 'range_compressor', '~> 1.0'
13
+ gem 'regexp_parser', '~> 2.1'
14
+ gem 'regexp_property_values', '~> 1.0'
15
+ gem 'rspec', '~> 3.8'
16
+ if RUBY_VERSION.to_f >= 2.7
17
+ gem 'codecov', '~> 0.2.12'
18
+ gem 'gouteur', '~> 1.0.0'
19
+ gem 'rubocop', '~> 1.8'
20
+ end
data/README.md CHANGED
@@ -5,16 +5,17 @@
5
5
  [![Build Status](https://github.com/jaynetics/character_set/workflows/gouteur/badge.svg)](https://github.com/jaynetics/character_set/actions)
6
6
  [![codecov](https://codecov.io/gh/jaynetics/character_set/branch/master/graph/badge.svg)](https://codecov.io/gh/jaynetics/character_set)
7
7
 
8
- This is a C-extended Ruby gem to work with sets of Unicode codepoints. It can read and write these sets in various formats and implements the stdlib `Set` interface for them.
8
+ This is a C-extended Ruby gem to work with sets of Unicode codepoints.
9
9
 
10
- It also offers an alternate paradigm of `String` processing which grants much better performance than `Regexp` and `String` methods from the stdlib where applicable (see [benchmarks](./BENCHMARK.md)).
10
+ It can [read](#parseinitialize) and [write](#write) sets of codepoints in various formats and it implements the stdlib `Set` interface for them.
11
+
12
+ It also offers a [way of scrubbing and scanning characters in Strings](#interact-with-strings) that is more semantic and consistently offers better performance than `Regexp` and `String` methods from the stdlib for this (see [benchmarks](./BENCHMARK.md)).
11
13
 
12
14
  Many parts can be used independently, e.g.:
13
15
  - `CharacterSet::Character`
14
16
  - `CharacterSet::ExpressionConverter`
15
17
  - `CharacterSet::Parser`
16
18
  - `CharacterSet::Writer`
17
- - [`RangeCompressor`](https://github.com/jaynetics/range_compressor)
18
19
 
19
20
  ## Usage
20
21
 
@@ -42,9 +43,10 @@ CharacterSet.parse('[a-c]')
42
43
  CharacterSet.parse('\U00000061-\U00000063')
43
44
  ```
44
45
 
45
- If the gems [`regexp_parser`](https://github.com/ammar/regexp_parser) and [`regexp_property_values`](https://github.com/jaynetics/regexp_property_values) are installed, `::of_regexp` and `::of_property` can also be used. `::of_regexp` can handle intersections, negations, and set nesting. Regexp's `i`-flag is ignored; call `#case_insensitive` on the result if needed.
46
+ If the gems [`regexp_parser`](https://github.com/ammar/regexp_parser) and [`regexp_property_values`](https://github.com/jaynetics/regexp_property_values) are installed, `Regexp` and unicode property names can also be read. Regexp intersections, negations, and set nesting are covered, but the `i`-flag is ignored; call `#case_insensitive` on the result if needed.
46
47
 
47
48
  ```ruby
49
+ CharacterSet.of(/./) # => #<CharacterSet (size: 1112064)>
48
50
  CharacterSet.of_property('Thai') # => #<CharacterSet (size: 86)>
49
51
 
50
52
  require 'character_set/core_ext/regexp_ext'
@@ -94,7 +96,7 @@ string # => ''
94
96
 
95
97
  ```ruby
96
98
  CharacterSet.non_ascii.count_in('Tüür') # => 2
97
- CharacterSet.non_ascii.scan_in('Tüür') # => ['ü', 'ü']
99
+ CharacterSet.non_ascii.scan('Tüür') # => ['ü', 'ü']
98
100
  ```
99
101
 
100
102
  There is also a core extension for String interaction.
@@ -145,6 +147,7 @@ CharacterSet['1', 'A'].case_insensitive # => CharacterSet['1', 'A', 'a']
145
147
  ```
146
148
 
147
149
  ### Write
150
+
148
151
  ```ruby
149
152
  set = CharacterSet['a', 'b', 'c', 'j', '-']
150
153
 
@@ -211,6 +214,6 @@ CharacterSet['a', 'ü', '🤩'].member_in_plane?(7) # => false
211
214
  CharacterSet::Character.new('a').plane # => 0
212
215
  ```
213
216
 
214
- ### Contributions
217
+ ## Contributions
215
218
 
216
219
  Feel free to send suggestions, point out issues, or submit pull requests.
data/Rakefile CHANGED
@@ -3,6 +3,8 @@ require 'rspec/core/rake_task'
3
3
  require 'rubygems/package_task'
4
4
  require 'rake/extensiontask'
5
5
 
6
+ Dir['tasks/**/*.rake'].each { |file| load(file) }
7
+
6
8
  RSpec::Core::RakeTask.new(:spec)
7
9
 
8
10
  task default: :spec
@@ -34,126 +36,6 @@ end
34
36
 
35
37
  task package: 'java:gem'
36
38
 
37
- desc 'Download relevant ruby/spec tests, adapt to CharacterSet and its variants'
38
- task :sync_ruby_spec do
39
- require 'fileutils'
40
-
41
- variants = {
42
- 'CharacterSet' => './spec/ruby-spec/library/character_set',
43
- 'CharacterSet::Pure' => './spec/ruby-spec/library/character_set_pure',
44
- }
45
-
46
- # download fresh specs from ruby/spec repository
47
- variants.each do |_, dir|
48
- FileUtils.rm_rf(dir) if File.exist?(dir)
49
- `svn export https://github.com/ruby/spec/trunk/library/set/sortedset #{dir}`
50
- end
51
-
52
- # make copies for each CharacterSet variant
53
- base = variants.first[1]
54
- variants.each_value { |dir| FileUtils.copy_entry(base, dir) unless dir == base }
55
-
56
- # adapt specs to work with CharacterSet
57
- variants.each do |class_name, dir|
58
- Dir["#{dir}/**/*.rb"].each do |spec|
59
- # ignore some tests that do not apply or are covered otherwise
60
- if spec =~ %r{/(classify|divide|flatten|initialize|pretty_print)}
61
- File.delete(spec)
62
- next
63
- end
64
-
65
- adapted_content =
66
- File.read(spec).
67
- # adapt class name
68
- gsub('SortedSet', (spec['/shared/'] ? 'variant' : class_name)).
69
- gsub(/(it_behaves_like :[^,\n]+), (:[^,\n]+)/, "\\1, #{class_name}, \\2").
70
- # get shared specs from a single shared dir at the parent level
71
- gsub(/(require_relative ['"])(shared\/)/, '\1../\2').
72
- # make 'mspec' syntax rspec-compatible
73
- gsub(/describe (.*), shared.*$/, 'shared_examples \1 do |variant, method|').
74
- gsub(/be_(false|true)/, 'be \1').
75
- gsub('stub!', 'stub').
76
- gsub('mock', 'double').
77
- gsub('@method', 'method').
78
- # remove unneeded requires
79
- gsub(/require 'set'\n/, '').
80
- gsub(/require.*spec_helper.*\n/, '').
81
- gsub(/\A\n+/, '').
82
- # make examples use Integers/codepoints
83
- gsub(/1\.0|"cat"|"dog"|"hello"|"test"/, '0').
84
- gsub('"one"', '1').
85
- gsub('"two"', '2').
86
- gsub('"three"', '3').
87
- gsub('"four"', '4').
88
- gsub('"five"', '5').
89
- gsub(/x.(size|length) == 3/, 'x != 3').
90
- gsub(/x.(size|length) != 3/, 'x == 3').
91
- gsub(/(add)\(\d\)(\.to_a \}.should raise)/, '\1(:foo)\2')
92
-
93
- File.open(spec, 'w') { |f| f.puts adapted_content }
94
- end
95
- end
96
-
97
- # keep only one copy of the shared specs, at the parent level
98
- FileUtils.rm_rf(base + '/../shared')
99
- FileUtils.mv(base + '/shared', base + '/../')
100
- variants.each_value { |dir| FileUtils.rm_rf(dir + '/shared') }
101
- end
102
-
103
- desc 'Download unicode casefold data and write new C header file'
104
- task :sync_casefold_data do
105
- src_path = './CaseFolding.txt'
106
- dst_path = './ext/character_set/unicode_casefold_table.h'
107
-
108
- `wget http://www.unicode.org/Public/UNIDATA/CaseFolding.txt`
109
-
110
- mapping = File.foreach(src_path).each_with_object({}) do |line, hash|
111
- from, type, to = line.split(/\s*;\s*/).first(3)
112
- # type 'C' stands for 'common', excludes mappings to multiple chars
113
- hash[from] = to if type == 'C'
114
- end.sort
115
-
116
- content = File.read(dst_path + '.tmpl')
117
- .sub(/(CASEFOLD_COUNT )0/, "\\1#{mapping.count}")
118
- .sub('{}', ['{', mapping.map { |a, b| "{0x#{a},0x#{b}}," }, '}'].join("\n"))
119
-
120
- File.write(dst_path, content)
121
- File.unlink(src_path)
122
- end
123
-
124
- desc 'Update codepoint data for predefined sets, based on Onigmo'
125
- task :sync_predefined_sets do
126
- %w[assigned emoji whitespace].each do |prop|
127
- require 'regexp_property_values'
128
- ranges = RegexpPropertyValues[prop].matched_ranges
129
- str = ranges.map { |r| "#{r.min.to_s(16)},#{r.max.to_s(16)}\n" }.join.upcase
130
- File.write("./lib/character_set/predefined_sets/#{prop}.cps", str, mode: 'w')
131
- end
132
- end
133
-
134
- desc 'Run all IPS benchmarks'
135
- task :benchmark do
136
- Dir['./benchmarks/*.rb'].sort.each { |file| require file }
137
- end
138
-
139
- namespace :benchmark do
140
- desc 'Run all IPS benchmarks and store the comparison results in BENCHMARK.md'
141
- task :write_to_file do
142
- $store_comparison_results = {}
143
-
144
- Rake.application[:benchmark].invoke
145
-
146
- File.open('BENCHMARK.md', 'w') do |f|
147
- f.puts "Results of `rake:benchmark` on #{RUBY_DESCRIPTION}", ''
148
-
149
- $store_comparison_results.each do |caption, result|
150
- f.puts '```', caption, '',
151
- result.strip.gsub(/(same-ish).*$/, '\1').lines[1..-1], '```'
152
- end
153
- end
154
- end
155
- end
156
-
157
39
  unless RUBY_PLATFORM =~ /java/
158
40
  # recompile before benchmarking or running specs
159
41
  task(:benchmark).enhance([:compile])
@@ -21,25 +21,4 @@ Gem::Specification.new do |s|
21
21
  s.extensions = %w[ext/character_set/extconf.rb]
22
22
 
23
23
  s.required_ruby_version = '>= 2.1.0'
24
-
25
- # SortedSet, needed for RubyFallback, was moved to a gem in Ruby 3.
26
- # This dependency is only used if the C extension is unavailable.
27
- # JRuby has it in the stdlib.
28
- if RUBY_VERSION.to_f >= 3.0 && !RUBY_PLATFORM[/java/i]
29
- s.add_dependency 'sorted_set', '~> 1.0'
30
- end
31
-
32
- s.add_development_dependency 'benchmark-ips', '~> 2.7'
33
- s.add_development_dependency 'get_process_mem', '~> 0.2.3'
34
- s.add_development_dependency 'rake', '~> 13.0'
35
- s.add_development_dependency 'rake-compiler', '~> 1.1'
36
- s.add_development_dependency 'range_compressor', '~> 1.0'
37
- s.add_development_dependency 'regexp_parser', '~> 2.1'
38
- s.add_development_dependency 'regexp_property_values', '~> 1.0'
39
- s.add_development_dependency 'rspec', '~> 3.8'
40
- if RUBY_VERSION.to_f >= 2.7
41
- s.add_development_dependency 'codecov', '~> 0.2.12'
42
- s.add_development_dependency 'gouteur', '~> 1.0.0'
43
- s.add_development_dependency 'rubocop', '~> 1.8'
44
- end
45
24
  end