strings-truncation 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3837ca8b06eb6173b46ec33382369c9cb6f1f1a78515cf318658dfdf2f3dbce1
4
+ data.tar.gz: 49be33a7cc3f22afbf77c2f168704f46234b5312ada53a4aefcdb4d315143e14
5
+ SHA512:
6
+ metadata.gz: 6308a3c890c3fd4f603399eb27cbe7faba13dbbc318497a3974d2db31ea3ed2827056162fb96eec522fc4dcbf2cd7b3e1eb84293500a041a8bcdbf349a554a9e
7
+ data.tar.gz: abf85e81c7fff5e9d0036c9e039a5880de95fcf9fdceef2d24abbeb908be8d6e07fdd09010d2e1a37e95e2b28395ccea7791d6c456c1772302e0fd62d5ebd9e0
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Change log
2
+
3
+ ## [v0.1.0] - 2020-02-23
4
+
5
+ * Initial implementation and release
6
+
7
+ [v0.1.0]: https://github.com/piotrmurach/strings-truncation/compare/efb1d50...v0.1.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Piotr Murach
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,247 @@
1
+ <div align="center">
2
+ <img width="225" src="https://github.com/piotrmurach/strings/blob/master/assets/strings_logo.png" alt="strings logo" />
3
+ </div>
4
+
5
+ # Strings::Truncation
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/strings-truncation.svg)][gem]
8
+ [![Actions CI](https://github.com/piotrmurach/strings-truncation/workflows/CI/badge.svg?branch=master)][gh_actions_ci]
9
+ [![Build status](https://ci.appveyor.com/api/projects/status/s8y94c4tvi8mgrh2?svg=true)][appveyor]
10
+ [![Maintainability](https://api.codeclimate.com/v1/badges/f7ecb5bf87696e522ccb/maintainability)][codeclimate]
11
+ [![Coverage Status](https://coveralls.io/repos/github/piotrmurach/strings-truncation/badge.svg?branch=master)][coverage]
12
+ [![Inline docs](http://inch-ci.org/github/piotrmurach/strings-truncation.svg?branch=master)][inchpages]
13
+
14
+ [gem]: http://badge.fury.io/rb/strings-truncation
15
+ [gh_actions_ci]: https://github.com/piotrmurach/strings-truncation/actions?query=workflow%3ACI
16
+ [appveyor]: https://ci.appveyor.com/project/piotrmurach/strings-truncation
17
+ [codeclimate]: https://codeclimate.com/github/piotrmurach/strings-truncation/maintainability
18
+ [coverage]: https://coveralls.io/github/piotrmurach/strings-truncation?branch=master
19
+ [inchpages]: http://inch-ci.org/github/piotrmurach/strings-truncation
20
+
21
+ > Truncate strings with fullwidth characters and ANSI codes.
22
+
23
+ ## Features
24
+
25
+ * No monkey-patching String class
26
+ * Omit text from the start, middle, end or both ends
27
+ * Account for fullwidth characters in encodings such as UTF-8, EUC-JP
28
+ * Shorten text without whitespaces between words (Chinese, Japanese, Korean etc)
29
+ * Preserve ANSI escape codes
30
+
31
+ ## Contents
32
+
33
+ * [1. Usage](#1-usage)
34
+ * [2. API](#2-api)
35
+ * [2.1 configure](#21-configure)
36
+ * [2.2 truncate](#22-truncate)
37
+ * [3. Extending String class](#3-extending-string-class)
38
+
39
+ ## Installation
40
+
41
+ Add this line to your application's Gemfile:
42
+
43
+ ```ruby
44
+ gem "strings-truncation"
45
+ ```
46
+
47
+ And then execute:
48
+
49
+ $ bundle
50
+
51
+ Or install it yourself as:
52
+
53
+ $ gem install strings-truncation
54
+
55
+ ## 1. Usage
56
+
57
+ Use `truncate` to shorten string to 30 characters by default:
58
+
59
+ ```ruby
60
+ strings = Strings::Truncation.new
61
+ strings.truncate("I try all things, I achieve what I can.")
62
+ # => "I try all things, I achieve w…"
63
+ ```
64
+
65
+ As a convenience, you can call `truncate` method directly on a class:
66
+
67
+ ```ruby
68
+ Strings::Truncation.truncate("I try all things, I achieve what I can.")
69
+ # => "I try all things, I achieve w…"
70
+ ```
71
+
72
+ To change the default truncation length, pass an integer as a second argument:
73
+
74
+ ```ruby
75
+ strings.truncate("I try all things, I achieve what I can.", 15)
76
+ # => "I try all thin…"
77
+ ```
78
+
79
+ Or if you want to be more explicit and flexible use `:length` keyword:
80
+
81
+ ```ruby
82
+ strings.truncate("I try all things, I achieve what I can.", length: 15)
83
+ # => "I try all thin…"
84
+ ```
85
+
86
+ You can specify custom omission string in place of default `…`:
87
+
88
+ ```ruby
89
+ strings.truncate("I try all things, I achieve what I can.", omission: "...")
90
+ # => "I try all things, I achieve..."
91
+ ```
92
+
93
+ If you wish to truncate preserving words use a string or regexp as a separator:
94
+
95
+ ```ruby
96
+ strings.truncate("I try all things, I achieve what I can.", separator: /\s/)
97
+ # => "I try all things, I achieve…"
98
+ ```
99
+
100
+ You can omit text from the `start`, `middle`, `end` or both `ends`:
101
+
102
+ ```ruby
103
+ strings.truncate("I try all things, I achieve what I can", position: :middle)
104
+ # => "I try all thing…ve what I can."
105
+ ```
106
+
107
+ You can truncate text with fullwidth characters (Chinese, Japanese, Korean etc):
108
+
109
+ ```ruby
110
+ strings.truncate("おはようございます", 8)
111
+ # => "おはよ…"
112
+ ```
113
+
114
+ As well as truncate text that contains ANSI escape codes:
115
+
116
+ ```ruby
117
+ strings.truncate("\e[34mI try all things, I achieve what I can\e[0m", 18)
118
+ # => "\e[34mI try all things,\e[0m…"
119
+ ```
120
+
121
+ ## 2. API
122
+
123
+ ### 2.1 configure
124
+
125
+ To change default configuration settings at initialization use keyword arguments.
126
+
127
+ For example, to omit text from the start and separate on a whitespace character do:
128
+
129
+ ```ruby
130
+ strings = Strings::Truncation.new(position: :start, separator: /\s/)
131
+ ```
132
+
133
+ After initialization, you can use `configure` to change settings inside a block:
134
+
135
+ ```ruby
136
+ strings.configure do |config|
137
+ config.length 25
138
+ config.omission "[...]"
139
+ config.position :start
140
+ config.separator /\s/
141
+ end
142
+ ```
143
+
144
+ Alternatively, you can also use `configure` with keyword arguments:
145
+
146
+ ```ruby
147
+ strings.configure(position: :start, separator: /\s/)
148
+ ```
149
+
150
+ ### 2.2 truncate
151
+
152
+ By default a string is truncated from the end to maximum length of `30` display columns.
153
+
154
+ ```ruby
155
+ strings.truncate("I try all things, I achieve what I can.")
156
+ # => "I try all things, I achieve w…"
157
+ ```
158
+
159
+ To change the default truncation length, pass an integer as a second argument:
160
+
161
+ ```ruby
162
+ strings.truncate("I try all things, I achieve what I can.", 15)
163
+ # => "I try all thin…"
164
+ ```
165
+
166
+ Or use `:length` keyword to be more explicit:
167
+
168
+ ```ruby
169
+ strings.truncate("I try all things, I achieve what I can.", length: 15)
170
+ # => "I try all thin…"
171
+ ```
172
+
173
+ The default `…` omission character can be replaced using `:omission`:
174
+
175
+ ```ruby
176
+ strings.truncate("I try all things, I achieve what I can.", omission: "...")
177
+ # => "I try all things, I achieve..."
178
+ ```
179
+
180
+ You can omit text from the `start`, `middle`, `end` or both `ends` by specifying `:position`:
181
+
182
+ ```ruby
183
+ strings.truncate("I try all things, I achieve what I can", position: :start)
184
+ # => "…things, I achieve what I can."
185
+
186
+ strings.truncate("I try all things, I achieve what I can", position: :middle)
187
+ # => "I try all thing…ve what I can."
188
+
189
+ strings.truncate("I try all things, I achieve what I can", position: :ends)
190
+ # => "… all things, I achieve what …"
191
+ ```
192
+
193
+ To truncate based on custom character(s) use `:separator` that accepts a string or regular expression:
194
+
195
+ ```ruby
196
+ strings.truncate("I try all things, I achieve what I can.", separator: /\s/)
197
+ => "I try all things, I achieve…"
198
+ ```
199
+
200
+ You can combine all settings to achieve desired result:
201
+
202
+ ```ruby
203
+ strings.truncate("I try all things, I achieve what I can.", length: 20,
204
+ omission: "...", position: :ends, separator: /\s/)
205
+ # => "...I achieve what..."
206
+ ```
207
+
208
+ ## 3. Extending String class
209
+
210
+ Though it is highly discouraged to pollute core Ruby classes, you can add the required methods to String class by using refinements.
211
+
212
+ To include all the **Strings::Truncation** methods, you can load extensions like so:
213
+
214
+ ```ruby
215
+ require "strings/truncation/extensions"
216
+
217
+ using Strings::Truncation::Extensions
218
+ ```
219
+
220
+ And then call `truncate` directly on any string:
221
+
222
+ ```ruby
223
+ "I try all things, I achieve what I can.".truncate(20, separator: " ")
224
+ # => "I try all things, I…"
225
+ ```
226
+
227
+ ## Development
228
+
229
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
230
+
231
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
232
+
233
+ ## Contributing
234
+
235
+ Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/strings-truncation. 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.
236
+
237
+ ## License
238
+
239
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
240
+
241
+ ## Code of Conduct
242
+
243
+ Everyone interacting in the Strings::Truncation project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/strings-truncation/blob/master/CODE_OF_CONDUCT.md).
244
+
245
+ ## Copyright
246
+
247
+ Copyright (c) 2019 Piotr Murach. See LICENSE for further details.
@@ -0,0 +1 @@
1
+ require "strings/truncation"
@@ -0,0 +1,368 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "strscan"
5
+ require "strings-ansi"
6
+ require "unicode/display_width"
7
+
8
+ require_relative "truncation/configuration"
9
+ require_relative "truncation/version"
10
+
11
+ module Strings
12
+ class Truncation
13
+ class Error < StandardError; end
14
+
15
+ ANSI_REGEXP = /#{Strings::ANSI::ANSI_MATCHER}/.freeze
16
+ RESET_REGEXP = /#{Regexp.escape(Strings::ANSI::RESET)}/.freeze
17
+ END_REGEXP = /\A(#{Strings::ANSI::ANSI_MATCHER})*\z/.freeze
18
+
19
+ # Global instance
20
+ #
21
+ # @api private
22
+ def self.__instance__
23
+ @__instance__ ||= Truncation.new
24
+ end
25
+
26
+ class << self
27
+ extend Forwardable
28
+
29
+ delegate %i[truncate] => :__instance__
30
+ end
31
+
32
+ # Create a Strings::Truncation instance
33
+ #
34
+ # @example
35
+ # strings = Strings::Truncation.new(separator: /[,- ]/)
36
+ #
37
+ # @param [Integer] length
38
+ # the maximum length to truncate to
39
+ # @param [String] omission
40
+ # the string to denote omitted content
41
+ # @param [String|Integer] position
42
+ # the position of the omission within the string
43
+ # @param [String|Regexp] separator
44
+ # the separator to break words on
45
+ #
46
+ # @api public
47
+ def initialize(**options)
48
+ configuration.update(**options)
49
+ end
50
+
51
+ # Access configuration
52
+ #
53
+ # @api public
54
+ def configuration
55
+ @configuration ||= Configuration.new
56
+ end
57
+
58
+ # Configure truncation
59
+ #
60
+ # @example
61
+ # strings = Strings::Truncation.new
62
+ # strings.configure do |config|
63
+ # config.length 20
64
+ # config.omission "[...]"
65
+ # config.position :middle
66
+ # config.separator /[,- ]/
67
+ # end
68
+ #
69
+ # @example
70
+ # strings = Strings::Truncation.new
71
+ # strings.configure length: 20, omission: "[...]"
72
+ #
73
+ # @yield [Configuration]
74
+ #
75
+ # @api public
76
+ def configure(**options)
77
+ if block_given?
78
+ yield configuration
79
+ else
80
+ configuration.update(**options)
81
+ end
82
+ end
83
+
84
+ # Truncate a text at a given length (defualts to 30)
85
+ #
86
+ # @param [String] text
87
+ # the text to be truncated
88
+ #
89
+ # @param [Integer] truncate_at
90
+ # the width at which to truncate the text
91
+ #
92
+ # @param [String|Regexp] separator
93
+ # the character for splitting words
94
+ #
95
+ # @param [String] omission
96
+ # the string to use for displaying omitted content
97
+ #
98
+ # @param [String|Integer] position
99
+ # the position in text from which to omit content
100
+ #
101
+ # @example
102
+ # truncate("It is not down on any map; true places never are.")
103
+ # # => "It is not down on any map; tr…""
104
+ #
105
+ # truncate("It is not down on any map; true places never are.", 15)
106
+ # # => "It is not down…""
107
+ #
108
+ # truncate("It is not down on any map; true places never are.",
109
+ # separator: " ")
110
+ # # => "It is not down on any map;…"
111
+ #
112
+ # truncate("It is not down on any map; true places never are.", 40,
113
+ # omission: "[...]")
114
+ # # => "It is not down on any map; true pla[...]"
115
+ #
116
+ # @api public
117
+ def truncate(text, truncate_at = configuration.length, length: nil,
118
+ position: configuration.position,
119
+ separator: configuration.separator,
120
+ omission: configuration.omission)
121
+ truncate_at = length if length
122
+
123
+ return text if truncate_at.nil? || text.bytesize <= truncate_at.to_i
124
+
125
+ return "" if truncate_at.zero?
126
+
127
+ separator = Regexp.new(separator) if separator
128
+
129
+ case position
130
+ when :start
131
+ truncate_start(text, truncate_at, omission, separator)
132
+ when :middle
133
+ truncate_middle(text, truncate_at, omission, separator)
134
+ when :ends
135
+ truncate_ends(text, truncate_at, omission, separator)
136
+ when :end
137
+ truncate_from(0, text, truncate_at, omission, separator)
138
+ when Numeric
139
+ truncate_from(position, text, truncate_at, omission, separator)
140
+ else
141
+ raise Error, "unsupported position: #{position.inspect}"
142
+ end
143
+ end
144
+
145
+ private
146
+
147
+ # Truncate text at the start
148
+ #
149
+ # @param [String] text
150
+ # the text to truncate
151
+ # @param [Integer] length
152
+ # the maximum length to truncate at
153
+ # @param [String] omission
154
+ # the string to denote omitted content
155
+ # @param [String|Regexp] separator
156
+ # the pattern or string to separate on
157
+ #
158
+ # @return [String]
159
+ # the truncated text
160
+ #
161
+ # @api private
162
+ def truncate_start(text, length, omission, separator)
163
+ text_width = display_width(Strings::ANSI.sanitize(text))
164
+ omission_width = display_width(omission)
165
+ return text if text_width == length
166
+ return omission if omission_width == length
167
+
168
+ from = [text_width - length, 0].max
169
+ from += omission_width if from > 0
170
+ words, = *slice(text, from, length - omission_width,
171
+ omission_width: omission_width,
172
+ separator: separator)
173
+
174
+ "#{omission if from > 0}#{words}"
175
+ end
176
+
177
+ # Truncate text before the from position and after the length
178
+ #
179
+ # @param [Integer] from
180
+ # the position to start extracting from
181
+ # @param [String] text
182
+ # the text to truncate
183
+ # @param [Integer] length
184
+ # the maximum length to truncate at
185
+ # @param [String] omission
186
+ # the string to denote omitted content
187
+ # @param [String|Regexp] separator
188
+ # the pattern or string to separate on
189
+ #
190
+ # @return [String]
191
+ # the truncated text
192
+ #
193
+ # @api private
194
+ def truncate_from(from, text, length, omission, separator)
195
+ omission_width = display_width(omission)
196
+ length_without_omission = length - omission_width
197
+ length_without_omission -= omission_width if from > 0
198
+ words, stop = *slice(text, from, length_without_omission,
199
+ omission_width: omission_width,
200
+ separator: separator)
201
+
202
+ "#{omission if from > 0}#{words}#{omission if stop}"
203
+ end
204
+
205
+ # Truncate text in the middle
206
+ #
207
+ # @param [String] text
208
+ # the text to truncate
209
+ # @param [Integer] length
210
+ # the maximum length to truncate at
211
+ # @param [String] omission
212
+ # the string to denote omitted content
213
+ # @param [String|Regexp] separator
214
+ # the pattern or string to separate on
215
+ #
216
+ # @return [String]
217
+ # the truncated text
218
+ #
219
+ # @api private
220
+ def truncate_middle(text, length, omission, separator)
221
+ text_width = display_width(Strings::ANSI.sanitize(text))
222
+ omission_width = display_width(omission)
223
+ return text if text_width == length
224
+ return omission if omission_width == length
225
+
226
+ half_length = length / 2
227
+ rem_length = half_length + length % 2
228
+ half_omission = omission_width / 2
229
+ rem_omission = half_omission + omission_width % 2
230
+
231
+ before_words, = *slice(text, 0, half_length - half_omission,
232
+ omission_width: half_omission,
233
+ separator: separator)
234
+
235
+ after_words, = *slice(text, text_width - rem_length + rem_omission,
236
+ rem_length - rem_omission,
237
+ omission_width: rem_omission,
238
+ separator: separator)
239
+
240
+ "#{before_words}#{omission}#{after_words}"
241
+ end
242
+
243
+ # Truncate text at both ends
244
+ #
245
+ # @param [String] text
246
+ # the text to truncate
247
+ # @param [Integer] length
248
+ # the maximum length to truncate at
249
+ # @param [String] omission
250
+ # the string to denote omitted content
251
+ # @param [String|Regexp] separator
252
+ # the pattern or string to separate on
253
+ #
254
+ # @return [String]
255
+ # the truncated text
256
+ #
257
+ # @api private
258
+ def truncate_ends(text, length, omission, separator)
259
+ text_width = display_width(Strings::ANSI.sanitize(text))
260
+ omission_width = display_width(omission)
261
+ return text if text_width <= length
262
+ return omission if length <= 2 * omission_width
263
+
264
+ from = (text_width - length) / 2 + omission_width
265
+ words, stop = *slice(text, from, length - 2 * omission_width,
266
+ omission_width: omission_width,
267
+ separator: separator)
268
+ return omission if words.empty?
269
+
270
+ "#{omission if from > 0}#{words}#{omission if stop}"
271
+ end
272
+
273
+ # Extract number of characters from a text starting at the from position
274
+ #
275
+ # @param [Integer] from
276
+ # the position to start from
277
+ # @param [Integer] length
278
+ # the number of characters to extract
279
+ # @param [Integer] omission_width
280
+ # the width of the omission
281
+ # @param [String|Regexp] separator
282
+ # the string or pattern to use for splitting words
283
+ #
284
+ # @return [Array<String, Boolean>]
285
+ # return a substring and a stop flag
286
+ #
287
+ # @api private
288
+ def slice(text, from, length, omission_width: 0, separator: nil)
289
+ scanner = StringScanner.new(text)
290
+ length_with_omission = length + omission_width
291
+ current_length = 0
292
+ start_position = 0
293
+ ansi_reset = false
294
+ visible_char = false
295
+ word_break = false
296
+ stop = false
297
+ words = []
298
+ word = []
299
+ char = nil
300
+
301
+ while !(scanner.eos? || stop)
302
+ if scanner.scan(RESET_REGEXP)
303
+ unless scanner.eos?
304
+ words << scanner.matched
305
+ ansi_reset = false
306
+ end
307
+ elsif scanner.scan(ANSI_REGEXP)
308
+ words << scanner.matched
309
+ ansi_reset = true
310
+ else
311
+ if (char =~ separator && start_position <= from) ||
312
+ separator && start_position.zero?
313
+ word_break = start_position != from
314
+ end
315
+
316
+ char = scanner.getch
317
+ char_width = display_width(char)
318
+ start_position += char_width
319
+ next if (start_position - char_width) < from
320
+
321
+ current_length += char_width
322
+
323
+ if char =~ separator
324
+ if word_break
325
+ word_break = false
326
+ current_length = 0
327
+ next
328
+ end
329
+ visible_char = true
330
+ words << word.join
331
+ word.clear
332
+ end
333
+
334
+ if current_length <= length || scanner.check(END_REGEXP) &&
335
+ current_length <= length_with_omission
336
+ if separator
337
+ word << char unless word_break
338
+ else
339
+ words << char
340
+ visible_char = true
341
+ end
342
+ else
343
+ stop = true
344
+ end
345
+ end
346
+ end
347
+
348
+ visible_char = true if !word.empty? && scanner.eos?
349
+
350
+ return ["", stop] unless visible_char
351
+
352
+ words << word.join if !word.empty? && scanner.eos?
353
+
354
+ words << Strings::ANSI::RESET if ansi_reset
355
+
356
+ [words.join, stop]
357
+ end
358
+
359
+ # Visible width of a string
360
+ #
361
+ # @return [Integer]
362
+ #
363
+ # @api private
364
+ def display_width(string)
365
+ Unicode::DisplayWidth.of(string)
366
+ end
367
+ end # Truncation
368
+ end # Strings
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strings
4
+ class Truncation
5
+ # A configuration object used by a Strings::Truncation instance
6
+ #
7
+ # @api private
8
+ class Configuration
9
+ DEFAULT_LENGTH = 30
10
+
11
+ DEFAULT_OMISSION = "…"
12
+
13
+ DEFAULT_POSITION = 0
14
+
15
+ # Create a configuration
16
+ #
17
+ # @api public
18
+ def initialize(length: DEFAULT_LENGTH, omission: DEFAULT_OMISSION,
19
+ position: DEFAULT_POSITION, separator: nil)
20
+ @length = length
21
+ @omission = omission
22
+ @position = position
23
+ @separator = separator
24
+ end
25
+
26
+ # Update current configuration
27
+ #
28
+ # @api public
29
+ def update(length: nil, omission: nil, position: nil, separator: nil)
30
+ @length = length if length
31
+ @omission = omission if omission
32
+ @position = position if position
33
+ @separator = separator if separator
34
+ end
35
+
36
+ # The maximum length to truncate to
37
+ #
38
+ # @example
39
+ # strings = Strings::Truncation.new
40
+ #
41
+ # strings.configure do |config|
42
+ # config.length 40
43
+ # end
44
+ #
45
+ # @param [Integer] number
46
+ #
47
+ # @api public
48
+ def length(number = (not_set = true))
49
+ if not_set
50
+ @length
51
+ else
52
+ @length = number
53
+ end
54
+ end
55
+
56
+ # The string to denote omitted content
57
+ #
58
+ # @example
59
+ # strings = Strings::Truncation.new
60
+ #
61
+ # strings.configure do |config|
62
+ # config.omission "..."
63
+ # end
64
+ #
65
+ # @param [String] string
66
+ #
67
+ # @api public
68
+ def omission(string = (not_set = true))
69
+ if not_set
70
+ @omission
71
+ else
72
+ @omission = string
73
+ end
74
+ end
75
+
76
+ # The position of the omission within the string
77
+ #
78
+ # @example
79
+ # strings = Strings::Truncation.new
80
+ #
81
+ # strings.configure do |config|
82
+ # config.position :start
83
+ # end
84
+ #
85
+ #
86
+ # @param [Symbol] position
87
+ # the position out of :start, :middle or :end
88
+ #
89
+ # @api public
90
+ def position(position = (not_set = true))
91
+ if not_set
92
+ @position
93
+ else
94
+ @position = position
95
+ end
96
+ end
97
+
98
+ # The separator to break the characters into words
99
+ #
100
+ # @example
101
+ # strings = Strings::Truncation.new
102
+ #
103
+ # strings.configure do |config|
104
+ # config.separator /[, ]/
105
+ # end
106
+ #
107
+ # @param [String|Regexp] separator
108
+ #
109
+ # @api public
110
+ def separator(separator = (not_set = true))
111
+ if not_set
112
+ @separator
113
+ else
114
+ @separator = separator
115
+ end
116
+ end
117
+ end # Configruation
118
+ end # Truncation
119
+ end # Strings
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../truncation"
4
+
5
+ module Strings
6
+ class Truncation
7
+ module Extensions
8
+ refine String do
9
+ def truncate(*args, **options)
10
+ Strings::Truncation.truncate(self, *args, **options)
11
+ end
12
+ end
13
+ end # Extensions
14
+ end # Truncation
15
+ end # Strings
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strings
4
+ class Truncation
5
+ VERSION = "0.1.0"
6
+ end # Truncation
7
+ end # Strings
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: strings-truncation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Piotr Murach
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-02-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: strings-ansi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: unicode-display_width
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '3.0'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '1.6'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rspec
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '3.0'
75
+ description: Truncate strings with fullwidth characters and ANSI codes. Characters
76
+ can be omitted from the start, middle, end or both ends.
77
+ email:
78
+ - piotr@piotrmurach.com
79
+ executables: []
80
+ extensions: []
81
+ extra_rdoc_files:
82
+ - README.md
83
+ - CHANGELOG.md
84
+ - LICENSE.txt
85
+ files:
86
+ - CHANGELOG.md
87
+ - LICENSE.txt
88
+ - README.md
89
+ - lib/strings-truncation.rb
90
+ - lib/strings/truncation.rb
91
+ - lib/strings/truncation/configuration.rb
92
+ - lib/strings/truncation/extensions.rb
93
+ - lib/strings/truncation/version.rb
94
+ homepage: https://github.com/piotrmurach/strings-truncation
95
+ licenses:
96
+ - MIT
97
+ metadata:
98
+ allowed_push_host: https://rubygems.org
99
+ bug_tracker_uri: https://github.com/piotrmurach/strings-truncation/issues
100
+ changelog_uri: https://github.com/piotrmurach/strings-truncation/blob/master/CHANGELOG.md
101
+ documentation_uri: https://www.rubydoc.info/gems/strings-truncation
102
+ homepage_uri: https://github.com/piotrmurach/strings-truncation
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: 2.0.0
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubygems_version: 3.1.2
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Truncate strings with fullwidth characters and ANSI codes.
122
+ test_files: []