strings-case 0.2.0 → 0.3.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: dc47bee251774eb57217a3fbac0028bd94ad6b44697f364c3d9fbb9e5f23c78c
4
- data.tar.gz: 6d2f3fc1a27f70387723cb362fa665bdb243dc948306d5d6e5021bcadaf316b2
3
+ metadata.gz: bec785e9ba89be06265c1bc10dc3e9523aedd7381f318439251f7100ff03d4f4
4
+ data.tar.gz: 7d3291105499505fcc5782e18f9c278b687a1b2dbd88b4342e5641601757dd3e
5
5
  SHA512:
6
- metadata.gz: 5c2a23a788a31480cdb8b099d39d5ec7ab58e9bbb8291810b4f89a1d34447a96f7883d599f056b91b85e8df19fbaf3c5503c3aa17e54efe543422ee1a4c23a3d
7
- data.tar.gz: 771199eab86b3a8c5e350b7b14787fe9e0b0645b583cf33465d46975dd4c97a542e02426014775fe46db287e3dac9932cbad67d68e30fc22ee504cea7d58e08c
6
+ metadata.gz: 7bee902c8bd54279c1d70e8592117eaf173f2c2920b0b7caa4d0e5006faf795771e82f834078bc1022b581d16df4b0fb9e60af928395c03bceb2265bac323d07
7
+ data.tar.gz: c533aaf5d4f0cbe6f88a18f66aef6f25254dac9ee753c2e4941a02c8cb4456a82b7bc09e68f05d9f7fcc26063fbef9ffd91366bfd76c489b7cf28e5bc34215ae
@@ -1,5 +1,13 @@
1
1
  # Change log
2
2
 
3
+ ## [v0.3.0] - 2019-12-07
4
+
5
+ ### Added
6
+ * Add performance tests
7
+
8
+ ### Changed
9
+ * Change to double parsing speed and halve object allocations
10
+
3
11
  ## [v0.2.0] - 2019-11-23
4
12
 
5
13
  ### Fixed
@@ -9,5 +17,6 @@
9
17
 
10
18
  * Initial implementation and release
11
19
 
20
+ [v0.3.0]: https://github.com/piotrmurach/strings-case/compare/v0.1.0...v0.3.0
12
21
  [v0.2.0]: https://github.com/piotrmurach/strings-case/compare/v0.1.0...v0.2.0
13
22
  [v0.1.0]: https://github.com/piotrmurach/strings-case/compare/v0.1.0
data/README.md CHANGED
@@ -265,7 +265,7 @@ Strings::Case.titlecase("HTTP response code", acronyms: ["HTTP"])
265
265
 
266
266
  Though it is highly discouraged to pollute core Ruby classes, you can add the required methods to `String` class by using refinements.
267
267
 
268
- For example, if you wish to only extend strings with `wrap` method do:
268
+ For example, if you wish to only extend strings with `snakecase` method do:
269
269
 
270
270
  ```ruby
271
271
  module MyStringExt
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "strscan"
4
+
3
5
  require_relative "case/version"
4
6
 
5
7
  module Strings
@@ -8,9 +10,11 @@ module Strings
8
10
  UP_LETTERS = ("A".."Z").freeze
9
11
  DOWN_LETTERS = ("a".."z").freeze
10
12
  DELIMITERS = [" ", "\n", "\t", "_", ".", "-", "#", "?", "!"].freeze
13
+ DELIMS = Regexp.union(DELIMITERS)
11
14
  NONALPHANUMERIC = (32..127).map(&:chr) -
12
15
  (DIGITS.to_a + DOWN_LETTERS.to_a + UP_LETTERS.to_a + DELIMITERS)
13
- UPCASE = /(?<!\p{Lu})\p{Lu}$/.freeze
16
+ NONALPHAS = Regexp.union(NONALPHANUMERIC)
17
+ UPPERCASE = /^(\p{Ll}|\p{Digit})\p{Lu}/.freeze
14
18
  LOWERCASE = /\p{Lu}(?=\p{Ll})/.freeze
15
19
 
16
20
  class Error < StandardError; end
@@ -258,45 +262,45 @@ module Strings
258
262
  def split_into_words(string, sep: nil)
259
263
  words = []
260
264
  word = []
261
- last = string.length - 1
262
-
263
- string.each_char.with_index do |char, i|
264
- combine = word[-1].to_s + char
265
+ scanner = StringScanner.new(string)
265
266
 
266
- if combine =~ UPCASE
267
+ while !scanner.eos?
268
+ if scanner.match?(UPPERCASE)
269
+ char = scanner.getch
267
270
  if word.size <= 1 # don't allow single letter words
268
271
  word << char
269
272
  else
273
+ word << char
270
274
  words << word.join
271
- word = [char]
275
+ word = []
272
276
  end
273
- elsif combine =~ LOWERCASE
274
- letter = word.pop
277
+ elsif scanner.match?(LOWERCASE)
278
+ char = scanner.getch
275
279
  if word.size <= 1 # don't allow single letter words
276
- word << letter << char
280
+ word << char
277
281
  else
278
282
  words << word.join
279
- word = [letter, char]
283
+ word = [char]
280
284
  end
281
- elsif DELIMITERS.include?(char)
285
+ elsif scanner.match?(DELIMS)
286
+ char = scanner.getch
282
287
  words << word.join unless word.empty?
283
- if i.zero? && char == sep
288
+ if scanner.pos == 1 && char == sep
284
289
  words << ""
290
+ elsif scanner.eos? && char == sep
291
+ word = [""]
285
292
  else
286
293
  word = []
287
294
  end
288
- elsif NONALPHANUMERIC.include?(char)
295
+ elsif scanner.skip(NONALPHAS)
289
296
  # noop
290
297
  else
291
- word << char
292
- end
293
-
294
- if last == i
295
- word = [""] if char == sep
296
- words << word.join unless word.empty?
298
+ word << scanner.getch
297
299
  end
298
300
  end
299
301
 
302
+ words << word.join unless word.empty?
303
+
300
304
  words
301
305
  end
302
306
  module_function :split_into_words
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Strings
4
4
  module Case
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec-benchmark"
4
+ require "active_support"
5
+
6
+ RSpec.describe Strings::Case do
7
+ include RSpec::Benchmark::Matchers
8
+
9
+ it "changes case" do
10
+ expect {
11
+ Strings::Case.snakecase("fooBarBaz")
12
+ }.to perform_slower_than {
13
+ ActiveSupport::Inflector.underscore("fooBarBaz")
14
+ }.at_most(2).times
15
+ end
16
+
17
+ it "allocates no more than 100 objects" do
18
+ expect {
19
+ Strings::Case.snakecase("fooBarBaz")
20
+ }.to perform_allocation(25)
21
+ end
22
+ end
@@ -18,6 +18,11 @@ begin
18
18
  RSpec::Core::RakeTask.new(:integration) do |task|
19
19
  task.pattern = "spec/integration{,/*/**}/*_spec.rb"
20
20
  end
21
+
22
+ desc "Run performance specs"
23
+ RSpec::Core::RakeTask.new(:perf) do |task|
24
+ task.pattern = "spec/perf{,/*/**}/*_spec.rb"
25
+ end
21
26
  end
22
27
 
23
28
  rescue LoadError
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strings-case
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-23 00:00:00.000000000 Z
11
+ date: 2019-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,6 +67,7 @@ files:
67
67
  - lib/strings/case.rb
68
68
  - lib/strings/case/extensions.rb
69
69
  - lib/strings/case/version.rb
70
+ - spec/perf/parsecase_spec.rb
70
71
  - spec/spec_helper.rb
71
72
  - spec/unit/camelcase_spec.rb
72
73
  - spec/unit/constcase_spec.rb