strings 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- # frozen_string_litera: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Strings
4
4
  # A class responsible for parsing padding value
@@ -45,7 +45,7 @@ module Strings
45
45
  elsif value.size == 4
46
46
  value
47
47
  else
48
- raise ParseError, 'Wrong :padding parameter, must be an array'
48
+ raise ParseError, "Wrong :padding parameter, must be an array"
49
49
  end
50
50
  end
51
51
 
@@ -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,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.4'
4
+ VERSION = "0.2.0"
5
5
  end # Strings
@@ -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.4
4
+ version: 0.2.0
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: 2018-09-10 00:00:00.000000000 Z
11
+ date: 2020-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: strings-ansi
@@ -16,98 +16,84 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.0
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.0
26
+ version: '0.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: unicode_utils
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.4.0
33
+ version: '1.4'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.4.0
40
+ version: '1.4'
41
41
  - !ruby/object:Gem::Dependency
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
- version: 1.4.0
47
+ version: '1.5'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.4.0
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '1.15'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '1.15'
54
+ version: '1.5'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: rake
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
- - - "~>"
59
+ - - ">="
74
60
  - !ruby/object:Gem::Version
75
- version: '10.0'
61
+ version: '0'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
- - - "~>"
66
+ - - ">="
81
67
  - !ruby/object:Gem::Version
82
- version: '10.0'
68
+ version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: rspec
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
- - - "~>"
73
+ - - ">="
88
74
  - !ruby/object:Gem::Version
89
75
  version: '3.0'
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
- - - "~>"
80
+ - - ">="
95
81
  - !ruby/object:Gem::Version
96
82
  version: '3.0'
97
- description: A set of useful functions such as fold, truncate, wrap and more for transoforming
98
- strings.
83
+ description: A set of methods for working with strings such as align, truncate, wrap
84
+ and many more.
99
85
  email:
100
- - ''
86
+ - piotr@piotrmurach.com
101
87
  executables: []
102
88
  extensions: []
103
- extra_rdoc_files: []
89
+ extra_rdoc_files:
90
+ - README.md
91
+ - CHANGELOG.md
92
+ - LICENSE.txt
104
93
  files:
105
94
  - CHANGELOG.md
106
95
  - LICENSE.txt
107
96
  - README.md
108
- - Rakefile
109
- - bin/console
110
- - bin/setup
111
97
  - lib/strings.rb
112
98
  - lib/strings/align.rb
113
99
  - lib/strings/extensions.rb
@@ -117,31 +103,15 @@ files:
117
103
  - lib/strings/truncate.rb
118
104
  - lib/strings/version.rb
119
105
  - 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: ''
106
+ homepage: https://github.com/piotrmurach/strings
142
107
  licenses:
143
108
  - MIT
144
- metadata: {}
109
+ metadata:
110
+ allowed_push_host: https://rubygems.org
111
+ changelog_uri: https://github.com/piotrmurach/strings/blob/master/CHANGELOG.md
112
+ documentation_uri: https://www.rubydoc.info/gems/strings
113
+ homepage_uri: https://github.com/piotrmurach/strings
114
+ source_code_uri: https://github.com/piotrmurach/strings
145
115
  post_install_message:
146
116
  rdoc_options: []
147
117
  require_paths:
@@ -150,16 +120,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
150
120
  requirements:
151
121
  - - ">="
152
122
  - !ruby/object:Gem::Version
153
- version: '0'
123
+ version: 2.0.0
154
124
  required_rubygems_version: !ruby/object:Gem::Requirement
155
125
  requirements:
156
126
  - - ">="
157
127
  - !ruby/object:Gem::Version
158
128
  version: '0'
159
129
  requirements: []
160
- rubyforge_project:
161
- rubygems_version: 2.7.3
130
+ rubygems_version: 3.1.2
162
131
  signing_key:
163
132
  specification_version: 4
164
- summary: A set of useful functions for transforming strings.
133
+ summary: A set of methods for working with strings.
165
134
  test_files: []