strings 0.1.5 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'strings-ansi'
4
- require 'unicode/display_width'
5
- require 'unicode_utils/each_grapheme'
3
+ require "strings-ansi"
4
+ require "unicode/display_width"
5
+ require "unicode_utils/each_grapheme"
6
6
 
7
7
  module Strings
8
8
  # A module responsible for text truncation
9
9
  module Truncate
10
- DEFAULT_TRAILING = ''.freeze
10
+ DEFAULT_TRAILING = "".freeze
11
11
 
12
12
  DEFAULT_LENGTH = 30
13
13
 
@@ -27,15 +27,15 @@ module Strings
27
27
  # text = "The sovereignest thing on earth is parmacetti for an inward bruise."
28
28
  #
29
29
  # Strings::Truncate.truncate(text)
30
- # # => "The sovereignest thing on ear…"
30
+ # # => "The sovereignest thing on ea…"
31
31
  #
32
32
  # Strings::Truncate.truncate(text, 20)
33
- # # => "The sovereignest th…"
33
+ # # => "The sovereignest t…"
34
34
  #
35
- # Strings::Truncate.truncate(text, 20, separator: ' ' )
35
+ # Strings::Truncate.truncate(text, 20, separator: " " )
36
36
  # # => "The sovereignest…"
37
37
  #
38
- # Strings::Truncate.truncate(40, trailing: '... (see more)' )
38
+ # Strings::Truncate.truncate(text, 40, trailing: "... (see more)" )
39
39
  # # => "The sovereignest thing on... (see more)"
40
40
  #
41
41
  # @api public
@@ -70,6 +70,7 @@ module Strings
70
70
  # @api private
71
71
  def shorten(original_chars, chars, length_without_trailing)
72
72
  truncated = []
73
+ return truncated if length_without_trailing.zero?
73
74
  char_width = display_width(chars[0])
74
75
  while length_without_trailing - char_width > 0
75
76
  orig_char = original_chars.shift
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Strings
4
- VERSION = '0.1.5'
4
+ VERSION = "0.2.1"
5
5
  end # Strings
data/lib/strings/wrap.rb CHANGED
@@ -1,55 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'strings-ansi'
4
- require 'unicode/display_width'
5
- require 'unicode_utils/each_grapheme'
6
-
7
- require_relative 'fold'
3
+ require "strings-ansi"
4
+ require "unicode/display_width"
5
+ require "unicode_utils/each_grapheme"
8
6
 
9
7
  module Strings
10
8
  module Wrap
11
9
  DEFAULT_WIDTH = 80
12
-
13
- NEWLINE = "\n".freeze
14
-
15
- SPACE = ' '.freeze
16
-
17
- LINE_BREAK = "\r\n+|\r+|\n+".freeze
10
+ NEWLINE = "\n"
11
+ SPACE = " "
12
+ LINE_BREAK = %r{\r\n|\r|\n}.freeze
13
+ LINE_BREAKS = "\r\n+|\r+|\n+"
18
14
 
19
15
  # Wrap a text into lines no longer than wrap_at length.
20
16
  # Preserves existing lines and existing word boundaries.
21
17
  #
22
18
  # @example
23
19
  # Strings::Wrap.wrap("Some longish text", 8)
24
- # # => >Some
25
- # >longish
26
- # >text
20
+ # # => "Some \nlongish \ntext"
27
21
  #
28
22
  # @api public
29
- def wrap(text, wrap_at = DEFAULT_WIDTH)
30
- if text.length < wrap_at.to_i || wrap_at.to_i.zero?
23
+ def wrap(text, wrap_at = DEFAULT_WIDTH, separator: NEWLINE)
24
+ if text.scan(/[[:print:]]/).length < wrap_at.to_i || wrap_at.to_i.zero?
31
25
  return text
32
26
  end
27
+
33
28
  ansi_stack = []
34
- text.split(%r{#{LINE_BREAK}}, -1).map do |paragraph|
35
- format_paragraph(paragraph, wrap_at, ansi_stack)
36
- end * NEWLINE
29
+ text.lines.map do |line|
30
+ format_line(line, wrap_at, ansi_stack).join(separator)
31
+ end.join
37
32
  end
38
33
  module_function :wrap
39
34
 
40
- # Format paragraph to be maximum of wrap_at length
35
+ # Format line to be maximum of wrap_at length
41
36
  #
42
- # @param [String] paragraph
43
- # the paragraph to format
37
+ # @param [String] text_line
38
+ # the line to format
44
39
  # @param [Integer] wrap_at
45
- # the maximum length to wrap the paragraph
40
+ # the maximum length to wrap the line
46
41
  #
47
42
  # @return [Array[String]]
48
43
  # the wrapped lines
49
44
  #
50
45
  # @api private
51
- def format_paragraph(paragraph, wrap_at, ansi_stack)
52
- cleared_para = Fold.fold(paragraph)
46
+ def format_line(text_line, wrap_at, ansi_stack)
53
47
  lines = []
54
48
  line = []
55
49
  word = []
@@ -58,10 +52,10 @@ module Strings
58
52
  word_length = 0
59
53
  line_length = 0
60
54
  char_length = 0 # visible char length
61
- text_length = display_width(cleared_para)
55
+ text_length = display_width(text_line)
62
56
  total_length = 0
63
57
 
64
- UnicodeUtils.each_grapheme(cleared_para) do |char|
58
+ UnicodeUtils.each_grapheme(text_line) do |char|
65
59
  # we found ansi let's consume
66
60
  if char == Strings::ANSI::CSI || ansi.length > 0
67
61
  ansi << char
@@ -70,7 +64,12 @@ module Strings
70
64
  elsif ansi_matched
71
65
  ansi_stack << [ansi[0...-1].join, line_length + word_length]
72
66
  ansi_matched = false
73
- ansi = []
67
+
68
+ if ansi.last == Strings::ANSI::CSI
69
+ ansi = [ansi.last]
70
+ else
71
+ ansi = []
72
+ end
74
73
  end
75
74
  next if ansi.length > 0
76
75
  end
@@ -91,65 +90,76 @@ module Strings
91
90
  end
92
91
 
93
92
  if char == SPACE # ends with space
94
- lines << insert_ansi(ansi_stack, line.join)
93
+ lines << insert_ansi(line.join, ansi_stack)
95
94
  line = []
96
95
  line_length = 0
97
96
  word << char
98
97
  word_length += char_length
99
98
  elsif word_length + char_length <= wrap_at
100
- lines << insert_ansi(ansi_stack, line.join)
99
+ lines << insert_ansi(line.join, ansi_stack)
101
100
  line = [word.join + char]
102
101
  line_length = word_length + char_length
103
102
  word = []
104
103
  word_length = 0
105
104
  else # hyphenate word - too long to fit a line
106
- lines << insert_ansi(ansi_stack, word.join)
105
+ lines << insert_ansi(word.join, ansi_stack)
107
106
  line_length = 0
108
107
  word = [char]
109
108
  word_length = char_length
110
109
  end
111
110
  end
112
- lines << insert_ansi(ansi_stack, line.join) unless line.empty?
113
- lines << insert_ansi(ansi_stack, word.join) unless word.empty?
111
+ lines << insert_ansi(line.join, ansi_stack) unless line.empty?
112
+ lines << insert_ansi(word.join, ansi_stack) unless word.empty?
114
113
  lines
115
114
  end
116
- module_function :format_paragraph
115
+ module_function :format_line
117
116
 
118
117
  # Insert ANSI code into string
119
118
  #
120
119
  # Check if there are any ANSI states, if present
121
120
  # insert ANSI codes at given positions unwinding the stack.
122
121
  #
123
- # @param [Array[Array[String, Integer]]] ansi_stack
124
- # the ANSI codes to apply
125
- #
126
122
  # @param [String] string
127
123
  # the string to insert ANSI codes into
128
124
  #
125
+ # @param [Array[Array[String, Integer]]] ansi_stack
126
+ # the ANSI codes to apply
127
+ #
129
128
  # @return [String]
130
129
  #
131
130
  # @api private
132
- def insert_ansi(ansi_stack, string)
131
+ def insert_ansi(string, ansi_stack = [])
133
132
  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
133
+ return string if string.empty?
134
+
135
+ new_stack = []
136
+ output = string.dup
137
+ length = string.size
138
+ matched_reset = false
139
+ ansi_reset = Strings::ANSI::RESET
140
+
141
+ # Reversed so that string index don't count ansi
142
+ ansi_stack.reverse_each do |ansi|
143
+ if ansi[0] =~ /#{Regexp.quote(ansi_reset)}/
144
+ matched_reset = true
145
+ output.insert(ansi[1], ansi_reset)
143
146
  next
144
- elsif !resetting
145
- reset_index = -1
146
- resetting = false
147
+ elsif !matched_reset # ansi without reset
148
+ matched_reset = false
149
+ new_stack << ansi # keep the ansi
150
+ next if ansi[1] == length
151
+ if output.end_with?(NEWLINE)
152
+ output.insert(-2, ansi_reset)
153
+ else
154
+ output.insert(-1, ansi_reset) # add reset at the end
155
+ end
147
156
  end
148
157
 
149
- color, color_index = *state
150
- output.insert(reset_index, Strings::ANSI::RESET).insert(color_index, color)
158
+ output.insert(ansi[1], ansi[0])
151
159
  end
152
- ansi_stack.pop(to_remove) # remove used states
160
+
161
+ ansi_stack.replace(new_stack)
162
+
153
163
  output
154
164
  end
155
165
  module_function :insert_ansi
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.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-29 00:00:00.000000000 Z
11
+ date: 2021-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: strings-ansi
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.1'
19
+ version: '0.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.1'
26
+ version: '0.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: unicode_utils
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -42,30 +42,22 @@ dependencies:
42
42
  name: unicode-display_width
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.5'
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '3.0'
48
51
  type: :runtime
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.5'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
54
  requirements:
59
55
  - - ">="
60
56
  - !ruby/object:Gem::Version
61
57
  version: '1.5'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
58
+ - - "<"
67
59
  - !ruby/object:Gem::Version
68
- version: '1.5'
60
+ version: '3.0'
69
61
  - !ruby/object:Gem::Dependency
70
62
  name: rake
71
63
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +86,20 @@ dependencies:
94
86
  - - ">="
95
87
  - !ruby/object:Gem::Version
96
88
  version: '3.0'
97
- description: A set of useful functions such as fold, truncate, wrap and more for transoforming
98
- strings.
89
+ description: A set of methods for working with strings such as align, truncate, wrap
90
+ and many more.
99
91
  email:
100
- - me@piotrmurach.com
92
+ - piotr@piotrmurach.com
101
93
  executables: []
102
94
  extensions: []
103
- extra_rdoc_files: []
95
+ extra_rdoc_files:
96
+ - README.md
97
+ - CHANGELOG.md
98
+ - LICENSE.txt
104
99
  files:
105
100
  - CHANGELOG.md
106
101
  - LICENSE.txt
107
102
  - README.md
108
- - Rakefile
109
- - bin/console
110
- - bin/setup
111
103
  - lib/strings.rb
112
104
  - lib/strings/align.rb
113
105
  - lib/strings/extensions.rb
@@ -117,31 +109,15 @@ files:
117
109
  - lib/strings/truncate.rb
118
110
  - lib/strings/version.rb
119
111
  - lib/strings/wrap.rb
120
- - spec/spec_helper.rb
121
- - spec/unit/align/align_left_spec.rb
122
- - spec/unit/align/align_right_spec.rb
123
- - spec/unit/align/align_spec.rb
124
- - spec/unit/align_spec.rb
125
- - spec/unit/ansi_spec.rb
126
- - spec/unit/extensions_spec.rb
127
- - spec/unit/fold/fold_spec.rb
128
- - spec/unit/fold_spec.rb
129
- - spec/unit/pad/pad_spec.rb
130
- - spec/unit/pad_spec.rb
131
- - spec/unit/padder/parse_spec.rb
132
- - spec/unit/sanitize_spec.rb
133
- - spec/unit/truncate/truncate_spec.rb
134
- - spec/unit/truncate_spec.rb
135
- - spec/unit/wrap/wrap_spec.rb
136
- - spec/unit/wrap_spec.rb
137
- - strings.gemspec
138
- - tasks/console.rake
139
- - tasks/coverage.rake
140
- - tasks/spec.rake
141
- homepage: ''
112
+ homepage: https://github.com/piotrmurach/strings
142
113
  licenses:
143
114
  - MIT
144
- metadata: {}
115
+ metadata:
116
+ allowed_push_host: https://rubygems.org
117
+ changelog_uri: https://github.com/piotrmurach/strings/blob/master/CHANGELOG.md
118
+ documentation_uri: https://www.rubydoc.info/gems/strings
119
+ homepage_uri: https://github.com/piotrmurach/strings
120
+ source_code_uri: https://github.com/piotrmurach/strings
145
121
  post_install_message:
146
122
  rdoc_options: []
147
123
  require_paths:
@@ -150,15 +126,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
150
126
  requirements:
151
127
  - - ">="
152
128
  - !ruby/object:Gem::Version
153
- version: '0'
129
+ version: 2.0.0
154
130
  required_rubygems_version: !ruby/object:Gem::Requirement
155
131
  requirements:
156
132
  - - ">="
157
133
  - !ruby/object:Gem::Version
158
134
  version: '0'
159
135
  requirements: []
160
- rubygems_version: 3.0.3
136
+ rubygems_version: 3.1.2
161
137
  signing_key:
162
138
  specification_version: 4
163
- summary: A set of useful functions for transforming strings.
139
+ summary: A set of methods for working with strings.
164
140
  test_files: []
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- require "bundler/gem_tasks"
2
-
3
- FileList['tasks/**/*.rake'].each(&method(:import))
4
-
5
- desc 'Run all specs'
6
- task ci: %w[ spec ]
7
-
8
- task default: :spec
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "strings"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
data/spec/spec_helper.rb DELETED
@@ -1,37 +0,0 @@
1
- if ENV['COVERAGE'] || ENV['TRAVIS']
2
- require 'simplecov'
3
- require 'coveralls'
4
-
5
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
- SimpleCov::Formatter::HTMLFormatter,
7
- Coveralls::SimpleCov::Formatter
8
- ]
9
-
10
- SimpleCov.start do
11
- command_name 'spec'
12
- add_filter 'spec'
13
- end
14
- end
15
-
16
- require "bundler/setup"
17
- require "strings"
18
-
19
- module Helpers
20
- def unindent(text)
21
- text.gsub(/^[ \t]*/, '').chomp
22
- end
23
- end
24
-
25
- RSpec.configure do |config|
26
- config.include(Helpers)
27
-
28
- # Enable flags like --only-failures and --next-failure
29
- config.example_status_persistence_file_path = ".rspec_status"
30
-
31
- # Disable RSpec exposing methods globally on `Module` and `main`
32
- config.disable_monkey_patching!
33
-
34
- config.expect_with :rspec do |c|
35
- c.syntax = :expect
36
- end
37
- end