strings 0.1.5 → 0.1.6

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: 59762ac60270a0fa21a1989b6ec1bf8b98eac632fc9ff8c091ef7dd711a8baf8
4
- data.tar.gz: 43276937aaef5a75cb43e8e29a6ea9f5f09b4488d22a84a03fa128de07840afb
3
+ metadata.gz: 921f81ef625130227be2240cdd40e00a88db1f902abd30af157833b31fc9e57c
4
+ data.tar.gz: f26a6ca02ea2a3fb59cd81c4347ee2381f7b745c1b80975ce8e3262d33b91a9e
5
5
  SHA512:
6
- metadata.gz: 29244946de99fa208749f9ca7f88010b70b466f0d29583f76b9b982b9b299a69b14a1f76a43cd537f46e758f2f7e3e40f057d6506650b67fcd84d6e788f127c0
7
- data.tar.gz: 6d8b306a59eaafb78308e293739dadaaded471ef2a97daffc3cf31681a490df05067845600faed4b2fdcf390aa307016934f07751a7d3aa5c5fff49363162812
6
+ metadata.gz: 03de4bc3bc330b62ea283a86904edf9a67d2921c1c42c12e12168f5b4d1d306cabd2bee7bbfc519e70bdbfc5f2a93f356aa99a47b830e1b28135d1f07b42ec36
7
+ data.tar.gz: 547a0b7849b8fa00db911f2e066cb0157f64cb5b169f64d5f62068f0e34be387b86bf862edefee08c6d98598d7f37f37416ea480bd58e2cff0338b1fb8ab31cc
@@ -1,5 +1,15 @@
1
1
  # Change log
2
2
 
3
+ ## [v0.1.6] - 2019-08-28
4
+
5
+ ### Changed
6
+ * Change Wrap#wrap, Align#align & Pad#pad to handle different line endings
7
+ * Change Pad#pad to pad empty lines
8
+
9
+ ### Fixed
10
+ * Fix Wrap#wrap to handle adjacent ANSI codes
11
+ * Fix Wrap#insert_ansi to handle nested ANSI codes
12
+
3
13
  ## [v0.1.5] - 2019-03-29
4
14
 
5
15
  ### Changed
@@ -30,6 +40,7 @@
30
40
 
31
41
  * Initial implementation and release
32
42
 
43
+ [v0.1.6]: https://github.com/piotrmurach/strings/compare/v0.1.4...v0.1.5
33
44
  [v0.1.5]: https://github.com/piotrmurach/strings/compare/v0.1.4...v0.1.5
34
45
  [v0.1.4]: https://github.com/piotrmurach/strings/compare/v0.1.3...v0.1.4
35
46
  [v0.1.3]: https://github.com/piotrmurach/strings/compare/v0.1.2...v0.1.3
data/README.md CHANGED
@@ -386,7 +386,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
386
386
 
387
387
  Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/strings. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
388
388
 
389
- 1. Fork it ( https://github.com/piotrmurach/verse/fork )
389
+ 1. Fork it ( https://github.com/piotrmurach/strings/fork )
390
390
  2. Create your feature branch (`git checkout -b my-new-feature`)
391
391
  3. Commit your changes (`git commit -am 'Add some feature'`)
392
392
  4. Push to the branch (`git push origin my-new-feature`)
@@ -7,8 +7,8 @@ module Strings
7
7
  # Responsible for text alignment
8
8
  module Align
9
9
  NEWLINE = "\n".freeze
10
-
11
- SPACE = ' '.freeze
10
+ SPACE = " ".freeze
11
+ LINE_BREAK = %r{\r\n|\r|\n}.freeze
12
12
 
13
13
  # Aligns text within the width.
14
14
  #
@@ -62,9 +62,11 @@ module Strings
62
62
  # @return [String]
63
63
  #
64
64
  # @api public
65
- def align_left(text, width, fill: SPACE, separator: NEWLINE)
65
+ def align_left(text, width, fill: SPACE, separator: nil)
66
66
  return if width.nil?
67
- each_line(text, separator) do |line|
67
+ sep = separator || text[LINE_BREAK] || NEWLINE
68
+
69
+ each_line(text, sep) do |line|
68
70
  width_diff = width - display_width(line)
69
71
  if width_diff > 0
70
72
  line + fill * width_diff
@@ -80,9 +82,11 @@ module Strings
80
82
  # @return [String]
81
83
  #
82
84
  # @api public
83
- def align_center(text, width, fill: SPACE, separator: NEWLINE)
85
+ def align_center(text, width, fill: SPACE, separator: nil)
84
86
  return text if width.nil?
85
- each_line(text, separator) do |line|
87
+ sep = separator || text[LINE_BREAK] || NEWLINE
88
+
89
+ each_line(text, sep) do |line|
86
90
  width_diff = width - display_width(line)
87
91
  if width_diff > 0
88
92
  right_count = (width_diff.to_f / 2).ceil
@@ -100,9 +104,11 @@ module Strings
100
104
  # @return [String]
101
105
  #
102
106
  # @api public
103
- def align_right(text, width, fill: SPACE, separator: NEWLINE)
107
+ def align_right(text, width, fill: SPACE, separator: nil)
104
108
  return text if width.nil?
105
- each_line(text, separator) do |line|
109
+ sep = separator || text[LINE_BREAK] || NEWLINE
110
+
111
+ each_line(text, sep) do |line|
106
112
  width_diff = width - display_width(line)
107
113
  if width_diff > 0
108
114
  fill * width_diff + line
@@ -9,8 +9,8 @@ module Strings
9
9
  # Responsible for text padding
10
10
  module Pad
11
11
  NEWLINE = "\n".freeze
12
-
13
- SPACE = ' '.freeze
12
+ SPACE = " ".freeze
13
+ LINE_BREAK = %r{\r\n|\r|\n}.freeze
14
14
 
15
15
  # Apply padding to multiline text with ANSI codes
16
16
  #
@@ -31,10 +31,11 @@ module Strings
31
31
  # @return [String]
32
32
  #
33
33
  # @api private
34
- def pad(text, padding, fill: SPACE, separator: NEWLINE)
34
+ def pad(text, padding, fill: SPACE, separator: nil)
35
35
  padding = Strings::Padder.parse(padding)
36
36
  text_copy = text.dup
37
- line_width = max_line_length(text, separator)
37
+ sep = separator || text[LINE_BREAK] || NEWLINE
38
+ line_width = max_line_length(text, sep)
38
39
  output = []
39
40
 
40
41
  filler_line = fill * line_width
@@ -43,7 +44,8 @@ module Strings
43
44
  output << pad_around(filler_line, padding, fill: fill)
44
45
  end
45
46
 
46
- text_copy.split(separator).each do |line|
47
+ text_copy.split(sep).each do |line|
48
+ line = line.empty? ? filler_line : line
47
49
  output << pad_around(line, padding, fill: fill)
48
50
  end
49
51
 
@@ -51,7 +53,7 @@ module Strings
51
53
  output << pad_around(filler_line, padding, fill: fill)
52
54
  end
53
55
 
54
- output.join(separator)
56
+ output.join(sep)
55
57
  end
56
58
  module_function :pad
57
59
 
@@ -72,7 +72,7 @@ module Strings
72
72
 
73
73
  # Set top padding
74
74
  #
75
- # @param [Integer] val
75
+ # @param [Integer] value
76
76
  #
77
77
  # @return [nil]
78
78
  #
@@ -92,7 +92,7 @@ module Strings
92
92
 
93
93
  # Set right padding
94
94
  #
95
- # @param [Integer] val
95
+ # @param [Integer] value
96
96
  #
97
97
  # @api public
98
98
  def right=(value)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Strings
4
- VERSION = '0.1.5'
4
+ VERSION = "0.1.6"
5
5
  end # Strings
@@ -9,12 +9,10 @@ require_relative 'fold'
9
9
  module Strings
10
10
  module Wrap
11
11
  DEFAULT_WIDTH = 80
12
-
13
12
  NEWLINE = "\n".freeze
14
-
15
- SPACE = ' '.freeze
16
-
17
- LINE_BREAK = "\r\n+|\r+|\n+".freeze
13
+ SPACE = " ".freeze
14
+ LINE_BREAK = %r{\r\n|\r|\n}.freeze
15
+ LINE_BREAKS = "\r\n+|\r+|\n+".freeze
18
16
 
19
17
  # Wrap a text into lines no longer than wrap_at length.
20
18
  # Preserves existing lines and existing word boundaries.
@@ -26,14 +24,15 @@ module Strings
26
24
  # >text
27
25
  #
28
26
  # @api public
29
- def wrap(text, wrap_at = DEFAULT_WIDTH)
30
- if text.length < wrap_at.to_i || wrap_at.to_i.zero?
27
+ def wrap(text, wrap_at = DEFAULT_WIDTH, separator: nil)
28
+ if text.scan(/[[:print:]]/).length < wrap_at.to_i || wrap_at.to_i.zero?
31
29
  return text
32
30
  end
33
31
  ansi_stack = []
34
- text.split(%r{#{LINE_BREAK}}, -1).map do |paragraph|
32
+ sep = separator || text[LINE_BREAK] || NEWLINE
33
+ text.split(%r{#{LINE_BREAKS}}, -1).map do |paragraph|
35
34
  format_paragraph(paragraph, wrap_at, ansi_stack)
36
- end * NEWLINE
35
+ end * sep
37
36
  end
38
37
  module_function :wrap
39
38
 
@@ -70,7 +69,12 @@ module Strings
70
69
  elsif ansi_matched
71
70
  ansi_stack << [ansi[0...-1].join, line_length + word_length]
72
71
  ansi_matched = false
73
- ansi = []
72
+
73
+ if ansi.last == Strings::ANSI::CSI
74
+ ansi = [ansi.last]
75
+ else
76
+ ansi = []
77
+ end
74
78
  end
75
79
  next if ansi.length > 0
76
80
  end
@@ -91,26 +95,26 @@ module Strings
91
95
  end
92
96
 
93
97
  if char == SPACE # ends with space
94
- lines << insert_ansi(ansi_stack, line.join)
98
+ lines << insert_ansi(line.join, ansi_stack)
95
99
  line = []
96
100
  line_length = 0
97
101
  word << char
98
102
  word_length += char_length
99
103
  elsif word_length + char_length <= wrap_at
100
- lines << insert_ansi(ansi_stack, line.join)
104
+ lines << insert_ansi(line.join, ansi_stack)
101
105
  line = [word.join + char]
102
106
  line_length = word_length + char_length
103
107
  word = []
104
108
  word_length = 0
105
109
  else # hyphenate word - too long to fit a line
106
- lines << insert_ansi(ansi_stack, word.join)
110
+ lines << insert_ansi(word.join, ansi_stack)
107
111
  line_length = 0
108
112
  word = [char]
109
113
  word_length = char_length
110
114
  end
111
115
  end
112
- lines << insert_ansi(ansi_stack, line.join) unless line.empty?
113
- lines << insert_ansi(ansi_stack, word.join) unless word.empty?
116
+ lines << insert_ansi(line.join, ansi_stack) unless line.empty?
117
+ lines << insert_ansi(word.join, ansi_stack) unless word.empty?
114
118
  lines
115
119
  end
116
120
  module_function :format_paragraph
@@ -120,36 +124,43 @@ module Strings
120
124
  # Check if there are any ANSI states, if present
121
125
  # insert ANSI codes at given positions unwinding the stack.
122
126
  #
123
- # @param [Array[Array[String, Integer]]] ansi_stack
124
- # the ANSI codes to apply
125
- #
126
127
  # @param [String] string
127
128
  # the string to insert ANSI codes into
128
129
  #
130
+ # @param [Array[Array[String, Integer]]] ansi_stack
131
+ # the ANSI codes to apply
132
+ #
129
133
  # @return [String]
130
134
  #
131
135
  # @api private
132
- def insert_ansi(ansi_stack, string)
136
+ def insert_ansi(string, ansi_stack = [])
133
137
  return string if ansi_stack.empty?
134
- to_remove = 0
135
- reset_index = -1
136
- output = string.dup
137
- resetting = false
138
- ansi_stack.reverse_each do |state|
139
- if state[0] =~ /#{Regexp.quote(Strings::ANSI::RESET)}/
140
- resetting = true
141
- reset_index = state[1]
142
- to_remove += 2
138
+ return string if string.empty?
139
+
140
+ new_stack = []
141
+ output = string.dup
142
+ length = string.size
143
+ matched_reset = false
144
+ ansi_reset = Strings::ANSI::RESET
145
+
146
+ # Reversed so that string index don't count ansi
147
+ ansi_stack.reverse_each do |ansi|
148
+ if ansi[0] =~ /#{Regexp.quote(ansi_reset)}/
149
+ matched_reset = true
150
+ output.insert(ansi[1], ansi_reset)
143
151
  next
144
- elsif !resetting
145
- reset_index = -1
146
- resetting = false
152
+ elsif !matched_reset # ansi without reset
153
+ matched_reset = false
154
+ new_stack << ansi # keep the ansi
155
+ next if ansi[1] == length
156
+ output.insert(-1, ansi_reset) # add reset at the end
147
157
  end
148
158
 
149
- color, color_index = *state
150
- output.insert(reset_index, Strings::ANSI::RESET).insert(color_index, color)
159
+ output.insert(ansi[1], ansi[0])
151
160
  end
152
- ansi_stack.pop(to_remove) # remove used states
161
+
162
+ ansi_stack.replace(new_stack)
163
+
153
164
  output
154
165
  end
155
166
  module_function :insert_ansi
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if ENV['COVERAGE'] || ENV['TRAVIS']
2
4
  require 'simplecov'
3
5
  require 'coveralls'
4
6
 
5
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
7
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
6
8
  SimpleCov::Formatter::HTMLFormatter,
7
9
  Coveralls::SimpleCov::Formatter
8
- ]
10
+ ])
9
11
 
10
12
  SimpleCov.start do
11
13
  command_name 'spec'
@@ -59,4 +59,13 @@ RSpec.describe Strings::Align, '#align_left' do
59
59
  "outdone by the madness of men***********"
60
60
  ].join)
61
61
  end
62
+
63
+ it "handles \r\n line separator" do
64
+ text = "Closes #360\r\n\r\nCloses !217"
65
+ expect(Strings::Align.align_left(text, 27)).to eq([
66
+ "Closes #360 ",
67
+ " ",
68
+ "Closes !217 "
69
+ ].join("\r\n"))
70
+ end
62
71
  end
@@ -59,4 +59,13 @@ RSpec.describe Strings::Align, '#align_right' do
59
59
  "***********outdone by the madness of men"
60
60
  ].join)
61
61
  end
62
+
63
+ it "handles \r\n line separator" do
64
+ text = "Closes #360\r\n\r\nCloses !217"
65
+ expect(Strings::Align.align_right(text, 27)).to eq([
66
+ " Closes #360",
67
+ " ",
68
+ " Closes !217"
69
+ ].join("\r\n"))
70
+ end
62
71
  end
@@ -74,4 +74,22 @@ RSpec.describe Strings::Align, '#align' do
74
74
  "*****outdone by the madness of men******"
75
75
  ].join)
76
76
  end
77
+
78
+ it "handles \r\n line separator" do
79
+ text = "Closes #360\r\n\r\nCloses !217"
80
+ expect(Strings::Align.align(text, 27)).to eq([
81
+ "Closes #360 ",
82
+ " ",
83
+ "Closes !217 "
84
+ ].join("\r\n"))
85
+ end
86
+
87
+ it "handles \r\n line separator and centers" do
88
+ text = "Closes #360\r\n\r\nCloses !217"
89
+ expect(Strings::Align.align_center(text, 27)).to eq([
90
+ " Closes #360 ",
91
+ " ",
92
+ " Closes !217 "
93
+ ].join("\r\n"))
94
+ end
77
95
  end
@@ -60,4 +60,15 @@ RSpec.describe Strings::Pad, '#pad' do
60
60
  " ",
61
61
  ].join("\n"))
62
62
  end
63
+
64
+ it "handles \r\n line separator" do
65
+ text = "Closes #360\r\n\r\nCloses !217"
66
+ expect(Strings::Pad.pad(text, [1,1,1,1])).to eq([
67
+ " ",
68
+ " Closes #360 ",
69
+ " ",
70
+ " Closes !217 ",
71
+ " "
72
+ ].join("\r\n"))
73
+ end
63
74
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "#insert_ansi" do
4
+ it "doesn't do anything when empty stack" do
5
+ text = "Ignorance is the parent of fear."
6
+
7
+ val = Strings::Wrap.insert_ansi(text, [])
8
+
9
+ expect(val).to eq(text)
10
+ end
11
+
12
+ it "inserts ANSI strings in a single line" do
13
+ text = "Ignorance is the parent of fear."
14
+ stack = [["\e[32;44m", 0], ["\e[0m", text.size]]
15
+
16
+ val = Strings::Wrap.insert_ansi(text, stack)
17
+
18
+ expect(val).to eq("\e[32;44mIgnorance is the parent of fear.\e[0m")
19
+ expect(stack).to eq([])
20
+ end
21
+
22
+ it "inserts ANSI strings with missing reset in a single line" do
23
+ text = "Ignorance is the parent of fear."
24
+ stack = [["\e[32;44m", 0]]
25
+
26
+ val = Strings::Wrap.insert_ansi(text, stack)
27
+
28
+ expect(val).to eq("\e[32;44mIgnorance is the parent of fear.\e[0m")
29
+ expect(stack).to eq([["\e[32;44m", 0]])
30
+ end
31
+
32
+ it "inserts 3 ansi strings in a single line" do
33
+ text = "Ignorance is the parent of fear."
34
+ stack = [
35
+ ["\e[32m", 0], ["\e[0m", 9],
36
+ ["\e[33m", 13], ["\e[0m", 16],
37
+ ["\e[34m", 27], ["\e[0m", 31]
38
+ ]
39
+
40
+ val = Strings::Wrap.insert_ansi(text, stack)
41
+
42
+ expect(val).to eq("\e[32mIgnorance\e[0m is \e[33mthe\e[0m parent of \e[34mfear\e[0m.")
43
+ expect(stack).to eq([])
44
+ end
45
+
46
+ it "inserts nested ANSI strings in a single line" do
47
+ text = "Ignorance is the parent of fear."
48
+ stack = [["\e[32m", 10], ["\e[33m", 17], ["\e[0m", 23], ["\e[0m", 26]]
49
+
50
+ val = Strings::Wrap.insert_ansi(text, stack)
51
+
52
+ expect(val).to eq("Ignorance \e[32mis the \e[33mparent\e[0m of\e[0m fear.")
53
+ expect(stack).to eq([])
54
+ end
55
+
56
+ it "removes matching pairs of ANSI codes only" do
57
+ text = "one"
58
+ stack = [["\e[32m", 0], ["\e[0m", 3], ["\e[33m", 3]]
59
+
60
+ val = Strings::Wrap.insert_ansi(text, stack)
61
+
62
+ expect(val).to eq("\e[32mone\e[0m")
63
+ expect(stack).to eq([["\e[33m", 3]])
64
+ end
65
+ end
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Strings::Wrap, '.wrap' do
4
4
  context 'when unicode' do
@@ -16,6 +16,18 @@ RSpec.describe Strings::Wrap, '.wrap' do
16
16
  expect(Strings::Wrap.wrap(text, 100)).to eq(text)
17
17
  end
18
18
 
19
+ it "wraps minimal width" do
20
+ str = "#?%"
21
+
22
+ val = Strings::Wrap.wrap(str, 1)
23
+
24
+ expect(val).to eq([
25
+ "#",
26
+ "?",
27
+ "%"
28
+ ].join("\n"))
29
+ end
30
+
19
31
  it "wraps correctly unbreakable words" do
20
32
  expect(Strings::Wrap.wrap('foobar1', 3)).to eq([
21
33
  "foo",
@@ -34,7 +46,7 @@ RSpec.describe Strings::Wrap, '.wrap' do
34
46
  " ",
35
47
  "conte",
36
48
  "nt "
37
- ].join("\n"))
49
+ ].join("\r\n"))
38
50
  end
39
51
 
40
52
  it "preserves newlines" do
@@ -113,6 +125,11 @@ RSpec.describe Strings::Wrap, '.wrap' do
113
125
  "も含み\n"
114
126
  ].join("\n"))
115
127
  end
128
+
129
+ it "handles \r\n line separator" do
130
+ text = "Closes #360\r\n\r\nCloses !217"
131
+ expect(Strings::Wrap.wrap(text, 15)).to eq(text)
132
+ end
116
133
  end
117
134
 
118
135
  context 'with ANSI codes' do
@@ -151,5 +168,40 @@ RSpec.describe Strings::Wrap, '.wrap' do
151
168
  "insulted me."
152
169
  ].join("\n"))
153
170
  end
171
+
172
+ it "applies ANSI codes when below wrap width" do
173
+ str = "\e[32mone\e[0m\e[33mtwo\e[0m"
174
+
175
+ val = Strings::Wrap.wrap(str, 6)
176
+
177
+ expect(val).to eq("\e[32mone\e[0m\e[33mtwo\e[0m")
178
+ end
179
+
180
+ xit "splits ANSI codes matching wrap width with space between codes" do
181
+ str = "\e[32mone\e[0m \e[33mtwo\e[0m"
182
+
183
+ val = Strings::Wrap.wrap(str, 3)
184
+
185
+ expect(val).to eq("\e[32mone\e[0m\n\e[33mtwo\e[0m")
186
+ end
187
+
188
+ xit "splits ANSI codes matching wrap width" do
189
+ str = "\e[32mone\e[0m\e[33mtwo\e[0m"
190
+
191
+ val = Strings::Wrap.wrap(str, 3)
192
+
193
+ expect(val).to eq("\e[32mone\e[0m\n\e[33mtwo\e[0m")
194
+ end
195
+
196
+ xit "wraps deeply nested ANSI codes correctly" do
197
+ str = "\e[32mone\e[33mtwo\e[0m\e[0m"
198
+
199
+ val = Strings::Wrap.wrap(str, 3)
200
+
201
+ expect(val).to eq([
202
+ "\e[32mone\e[0m",
203
+ "\e[33mtwo\e[0m",
204
+ ].join("\n"))
205
+ end
154
206
  end
155
207
  end
@@ -1,10 +1,8 @@
1
- # encoding: utf-8
2
-
3
- desc 'Load gem inside irb console'
1
+ desc "Load gem inside irb console"
4
2
  task :console do
5
- require 'irb'
6
- require 'irb/completion'
7
- require File.join(__FILE__, '../../lib/tty-reader')
3
+ require "irb"
4
+ require "irb/completion"
5
+ require File.join(__FILE__, "../../lib/strings")
8
6
  ARGV.clear
9
7
  IRB.start
10
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strings
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-29 00:00:00.000000000 Z
11
+ date: 2019-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: strings-ansi
@@ -132,6 +132,7 @@ files:
132
132
  - spec/unit/sanitize_spec.rb
133
133
  - spec/unit/truncate/truncate_spec.rb
134
134
  - spec/unit/truncate_spec.rb
135
+ - spec/unit/wrap/insert_ansi_spec.rb
135
136
  - spec/unit/wrap/wrap_spec.rb
136
137
  - spec/unit/wrap_spec.rb
137
138
  - strings.gemspec