indented_io 0.7.3 → 0.8.4
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 +4 -4
- data/README.md +32 -32
- data/TODO +8 -2
- data/indented_io.gemspec +1 -1
- data/lib/indented_io/indented_io.rb +23 -36
- data/lib/indented_io/indented_io_interface.rb +4 -3
- data/lib/indented_io/kernel.rb +1 -1
- data/lib/indented_io/stringio.rb +1 -0
- data/lib/indented_io/version.rb +1 -1
- data/scripts/perf.rb +12 -3
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2065a8b32b45c15d23fca5af4899cde35fefae5e1df980bfcf90423aa0884cc2
|
4
|
+
data.tar.gz: 83aad862d7eefe03af50b833f94579bcb67dd9a049d7827ac354949055d9fb9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a3e1eef0a3a6d2807504c4d000a39d08093bb44381ed6eac0c1d1ae5c7dccf5e60a0c00fd07316c19329e5e1f49fb3b4662adbfb0df82a55c0206f2d6915f4e
|
7
|
+
data.tar.gz: ba4d79601f35265184d85629a57773b34cca6b7913220c629d332b2762762dc946337f21b4ce9c4b896866ef8efa99b4a9d5748f27ce93a71c31a5d9a2c0e4ed
|
data/README.md
CHANGED
@@ -11,9 +11,9 @@ adds to the previous indendation
|
|
11
11
|
```ruby
|
12
12
|
require 'indented_io'
|
13
13
|
|
14
|
-
puts
|
15
|
-
indent { puts
|
16
|
-
indent(2,
|
14
|
+
puts 'Not indented'
|
15
|
+
indent { puts 'Indented one level' }
|
16
|
+
indent(2, '* ').puts 'Indented two levels'
|
17
17
|
```
|
18
18
|
|
19
19
|
outputs
|
@@ -32,9 +32,9 @@ If given a block, the block will be called with the IndentedIO object as
|
|
32
32
|
argument:
|
33
33
|
|
34
34
|
```ruby
|
35
|
-
$stdout.puts
|
36
|
-
$stdout.indent.puts
|
37
|
-
$stdout.indent { |f| f.puts
|
35
|
+
$stdout.puts 'Not indented'
|
36
|
+
$stdout.indent.puts 'Indented'
|
37
|
+
$stdout.indent { |f| f.puts 'Indented' }
|
38
38
|
|
39
39
|
# Not indented
|
40
40
|
# Indented
|
@@ -51,10 +51,10 @@ symbolic argument `:string`. If level is negative, the text will be outdented
|
|
51
51
|
instead:
|
52
52
|
|
53
53
|
```ruby
|
54
|
-
$stdout.puts
|
55
|
-
$stdout.indent(2,
|
56
|
-
f.indent(string:
|
57
|
-
f.indent(-1).puts
|
54
|
+
$stdout.puts 'Not indented'
|
55
|
+
$stdout.indent(2, '> ') do |f|
|
56
|
+
f.indent(string: '* ').puts 'Indented three levels'
|
57
|
+
f.indent(-1).puts 'Indented one level'
|
58
58
|
end
|
59
59
|
|
60
60
|
# Not indented
|
@@ -71,15 +71,15 @@ that `Kernel#print`, `Kernel#printf`, `Kernel#puts`, and `Kernel#p` will output
|
|
71
71
|
indented within that block:
|
72
72
|
|
73
73
|
```ruby
|
74
|
-
puts
|
74
|
+
puts 'Not indented'
|
75
75
|
indent do
|
76
|
-
puts
|
76
|
+
puts 'Indented one level'
|
77
77
|
indent do
|
78
|
-
puts
|
78
|
+
puts 'Indented two levels'
|
79
79
|
end
|
80
|
-
puts
|
80
|
+
puts 'Indented one level'
|
81
81
|
end
|
82
|
-
puts
|
82
|
+
puts 'Not indented'
|
83
83
|
|
84
84
|
# Not indented
|
85
85
|
# Indented one level
|
@@ -95,8 +95,8 @@ def legacy(phrase)
|
|
95
95
|
puts phrase
|
96
96
|
end
|
97
97
|
|
98
|
-
legacy(
|
99
|
-
indent { legacy(
|
98
|
+
legacy('Not indented')
|
99
|
+
indent { legacy('Indented' }
|
100
100
|
|
101
101
|
# Not indented
|
102
102
|
# Indented
|
@@ -111,8 +111,8 @@ that specify if the output device is at the beginning of a line and that printin
|
|
111
111
|
should start with an indentation string:
|
112
112
|
|
113
113
|
```ruby
|
114
|
-
indent(1, bol: true).puts
|
115
|
-
indent(1, bol: false).puts
|
114
|
+
indent(1, bol: true).puts 'Indented'
|
115
|
+
indent(1, bol: false).puts 'Not indented\nIndented'
|
116
116
|
|
117
117
|
# Indented
|
118
118
|
# Not indented
|
@@ -124,7 +124,7 @@ indent(1, bol: false).puts "Not indented\nIndented"
|
|
124
124
|
The default indentation string is defined in `IndentedIO`:
|
125
125
|
|
126
126
|
```ruby
|
127
|
-
IndentedIO.default_indent =
|
127
|
+
IndentedIO.default_indent = '>> '
|
128
128
|
indent.puts "Indented by #{IndentedIO.default_indent.inspect}"
|
129
129
|
|
130
130
|
# >> Indented by ">> "
|
@@ -142,19 +142,19 @@ In case of errors an `IndentedIO::Error` exception is raised
|
|
142
142
|
|
143
143
|
You can add support for your own IO objects by including
|
144
144
|
`IndentedIO::IndentedIOInterface` in your class. All that is required is that
|
145
|
-
the class define a `#
|
146
|
-
|
145
|
+
the class define a `#write` method with the same semantics as `IO#write`
|
146
|
+
(convert arguments to strings and then write them)
|
147
147
|
|
148
148
|
```ruby
|
149
149
|
require 'indented_io'
|
150
150
|
class MyIO
|
151
151
|
include IndentedIO::IndentedIOInterface
|
152
|
-
def
|
152
|
+
def write(*args) ... end
|
153
153
|
end
|
154
154
|
|
155
155
|
my_io = MyIO.new
|
156
|
-
my_io.puts
|
157
|
-
my_io.indent.puts
|
156
|
+
my_io.puts 'Not indented'
|
157
|
+
my_io.indent.puts 'It works!'
|
158
158
|
|
159
159
|
# Not indented
|
160
160
|
# It works!
|
@@ -168,13 +168,13 @@ with a block without parameters manipulates `$stdout`, replacing it with an
|
|
168
168
|
`IndentedIO` object for the duration of the block
|
169
169
|
|
170
170
|
The implementation carries no overhead if it is not used but the core
|
171
|
-
indentation mechanism processes characters one-by-one which is about
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
171
|
+
indentation mechanism processes characters one-by-one which is about 7-8 times
|
172
|
+
slower than a handwritten implementation (scripts/perf.rb is a script to check
|
173
|
+
performance). It would be much faster if the inner loop was implemented in C.
|
174
|
+
However, we're talking micro-seconds here: Printing without using IndentedIO
|
175
|
+
range from around 0.25us to 1us while using IndentedIO slows it down to between
|
176
|
+
2us and 8us, so IndentedIO won't cause a noticeable slow down of your
|
177
|
+
application unless you do a lot of output
|
178
178
|
|
179
179
|
## Installation
|
180
180
|
|
data/TODO
CHANGED
@@ -2,14 +2,20 @@
|
|
2
2
|
TODO
|
3
3
|
o Check if IO object is writable - no good solution ?
|
4
4
|
o better name for @this_indent ? 'string' ?
|
5
|
-
o Change dependency in IndentedIOInterface from #print to #write and bump
|
6
|
-
version to 0.8 as this is the last user-visible change to be made
|
7
5
|
o Reimplement core loop in C
|
8
6
|
o Create BaseIndentedIO to hold bol status and remove it from IndentedIO
|
9
7
|
o Transmogrify instances variables and protected methods in IndentedIO to
|
10
8
|
avoid collision with names from the underlying device
|
11
9
|
o Explain name collision issues in the docs
|
12
10
|
|
11
|
+
+ Remove IndentedIO#dump
|
12
|
+
+ Change dependency in IndentedIOInterface from #print to #write and bump
|
13
|
+
version to 0.8 as this is the last user-visible change to be made
|
14
|
+
+ Oops. #print reimplemention doesn't do this:
|
15
|
+
If the output field separator ($,) is not nil, it is inserted between
|
16
|
+
objects. If the output record separator ($\) is not nil, it is appended to
|
17
|
+
the output
|
18
|
+
+ Tests for #write
|
13
19
|
+ explain bol
|
14
20
|
+ Allow a symbolic :string argument
|
15
21
|
+ #printf !
|
data/indented_io.gemspec
CHANGED
@@ -37,6 +37,6 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.require_paths = ["lib"]
|
38
38
|
|
39
39
|
spec.add_development_dependency "bundler", "~> 1.16"
|
40
|
-
spec.add_development_dependency "rake", "
|
40
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
41
41
|
spec.add_development_dependency "rspec", "~> 3.0"
|
42
42
|
end
|
@@ -20,48 +20,48 @@ module IndentedIO
|
|
20
20
|
interface_indent(levels, string, bol: bol, &block)
|
21
21
|
end
|
22
22
|
|
23
|
+
# Indent and print args to the underlying device. #write has the same semantic
|
24
|
+
# as IO#write
|
25
|
+
def write(*args)
|
26
|
+
str = args.join
|
27
|
+
return if str.empty?
|
28
|
+
s = (bol && str[0] != "\n" ? @combined_indent : "") + str.gsub(/\n([^\n])/m, "\n#{@combined_indent}\\1")
|
29
|
+
self.bol = (s[-1] == "\n")
|
30
|
+
@device.write(s)
|
31
|
+
end
|
32
|
+
|
23
33
|
# Indent and print args to the underlying device. #print has the same semantic
|
24
34
|
# as Kernel#print
|
25
35
|
def print(*args)
|
26
|
-
if
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
args.join.each_char { |c|
|
31
|
-
if c == "\n"
|
32
|
-
self.bol = true
|
33
|
-
elsif bol
|
34
|
-
@device.print @combined_indent
|
35
|
-
self.bol = false
|
36
|
-
end
|
37
|
-
@device.print c
|
38
|
-
}
|
36
|
+
return nil if args.empty?
|
37
|
+
write(args.join($, || ''))
|
38
|
+
write($\) if $\
|
39
39
|
nil
|
40
40
|
end
|
41
41
|
|
42
42
|
# Indent and print args to the underlying device. #printf has the same semantic
|
43
43
|
# as Kernel#printf
|
44
44
|
def printf(format, *args)
|
45
|
-
|
45
|
+
write format % args
|
46
46
|
end
|
47
47
|
|
48
48
|
# Indent and print args to the underlying device. #puts has the same semantic
|
49
49
|
# as Kernel#puts
|
50
50
|
def puts(*args)
|
51
|
-
args.
|
51
|
+
write args.join("\n"), "\n"
|
52
52
|
nil
|
53
53
|
end
|
54
54
|
|
55
55
|
# Indent and print args to the underlying device. #p has the same semantic
|
56
|
-
# as Kernel#p. Please note that #p is
|
57
|
-
#
|
56
|
+
# as Kernel#p. Please note that #p is only defined on Kernel in the Ruby core
|
57
|
+
# library but can be used on any IndentedIO object
|
58
58
|
def p(*args)
|
59
59
|
if bol
|
60
|
-
args.each { |arg|
|
60
|
+
args.each { |arg| write(arg.inspect, "\n") }
|
61
61
|
else
|
62
|
-
@device.
|
62
|
+
@device.write(args.first.inspect, "\n")
|
63
63
|
bol = true
|
64
|
-
args[1..-1].each { |arg|
|
64
|
+
args[1..-1].each { |arg| write(arg.inspect, "\n") }
|
65
65
|
end
|
66
66
|
args.size == 1 ? args.first : args
|
67
67
|
end
|
@@ -69,7 +69,7 @@ module IndentedIO
|
|
69
69
|
# Make IndentedIO behave like the underlying @device
|
70
70
|
# @!visibility private
|
71
71
|
def respond_to?(method)
|
72
|
-
[:indent, :level, :print, :puts, :p].include?(method) || device.respond_to?(method)
|
72
|
+
[:indent, :level, :print, :printf, :puts, :p].include?(method) || device.respond_to?(method)
|
73
73
|
end
|
74
74
|
|
75
75
|
# Make IndentedIO behave like the underlying @device
|
@@ -85,8 +85,8 @@ module IndentedIO
|
|
85
85
|
attr_reader :device
|
86
86
|
|
87
87
|
# First IndentedIO object on the stack. Equal to self if self is the first
|
88
|
-
# indentation object. #base is used to keep track of #bol for
|
89
|
-
# stack of IndentedIO objects
|
88
|
+
# indentation object. The #base object is used to keep track of #bol for
|
89
|
+
# the whole stack of IndentedIO objects
|
90
90
|
attr_reader :base
|
91
91
|
|
92
92
|
# Parent IndentedIO or IO object
|
@@ -146,18 +146,5 @@ module IndentedIO
|
|
146
146
|
self.bol = (bol.nil? ? true : bol)
|
147
147
|
end
|
148
148
|
end
|
149
|
-
|
150
|
-
public
|
151
|
-
# @!visibility private
|
152
|
-
def dump
|
153
|
-
$stderr.puts "#{self.class} [#{self.object_id}]"
|
154
|
-
$stderr.puts " device: #{device.class} [#{device.object_id}]"
|
155
|
-
$stderr.puts " base : #{base.class} [#{base.object_id}]"
|
156
|
-
$stderr.puts " parent: #{parent.class} [#{parent.object_id}]"
|
157
|
-
$stderr.puts " levels: #{levels}"
|
158
|
-
$stderr.puts " this_indent: #{this_indent.inspect}"
|
159
|
-
$stderr.puts " combined_indent: #{combined_indent.inspect}"
|
160
|
-
$stderr.puts " bol: #{bol}"
|
161
|
-
end
|
162
149
|
end
|
163
150
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module IndentedIO
|
2
2
|
# IndentedIO interface that provides the #indent method. It is used by IO,
|
3
3
|
# StringIO, and IndentedIO but can be included in any class that define a
|
4
|
-
# #
|
4
|
+
# #write method like this:
|
5
5
|
#
|
6
6
|
# require 'indented_io'
|
7
|
+
#
|
7
8
|
# class MyIO
|
8
9
|
# include IndentedIO::IndentedIOInterface
|
9
|
-
# def
|
10
|
+
# def write(*args) ... end
|
10
11
|
# end
|
11
12
|
#
|
12
13
|
# my_io = MyIO.new
|
@@ -18,7 +19,7 @@ module IndentedIO
|
|
18
19
|
#
|
19
20
|
module IndentedIOInterface
|
20
21
|
# Returns a IndentedIO object that can be used for printing. The IO object
|
21
|
-
# will pass-through all
|
22
|
+
# will pass-through all methods to the underlying device except #print,
|
22
23
|
# #printf, #puts, and #p
|
23
24
|
#
|
24
25
|
# +level+ is the number of leves to indent and +string+ is the string used
|
data/lib/indented_io/kernel.rb
CHANGED
@@ -3,7 +3,7 @@ require 'indented_io/indented_io_interface'
|
|
3
3
|
module Kernel
|
4
4
|
# Like {IndentedIO::IndentedIOInterface#indent} except the underlying device is
|
5
5
|
# not the receiver (Kernel) but $stdout. Kernel#indent also allows a block without
|
6
|
-
#
|
6
|
+
# an argument. In that case it manipulates $stdout to print indented:
|
7
7
|
#
|
8
8
|
# puts "Not indented
|
9
9
|
# indent do
|
data/lib/indented_io/stringio.rb
CHANGED
data/lib/indented_io/version.rb
CHANGED
data/scripts/perf.rb
CHANGED
@@ -7,15 +7,24 @@ RUNS = 1_000_000
|
|
7
7
|
saved_stdout = $stdout
|
8
8
|
$stdout = File.open("/dev/null", "w")
|
9
9
|
|
10
|
-
|
10
|
+
$base = 0.0
|
11
|
+
|
12
|
+
def timeit_impl(&block)
|
11
13
|
t0 = Time.now
|
12
14
|
RUNS.times {
|
13
15
|
yield
|
14
16
|
}
|
15
17
|
t1 = Time.now
|
16
|
-
|
18
|
+
t1 - t0 - $base
|
17
19
|
end
|
18
20
|
|
21
|
+
$base = timeit_impl {}
|
22
|
+
|
23
|
+
def timeit(&block)
|
24
|
+
(1000 * timeit_impl(&block)).round(0)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
19
28
|
def report(title, wo_indent, w_indent)
|
20
29
|
times = (w_indent / wo_indent).round(1)
|
21
30
|
if times < 1.1
|
@@ -56,7 +65,7 @@ dynamic_wo_indent = timeit {
|
|
56
65
|
}
|
57
66
|
|
58
67
|
dynamic_w_indent = nil
|
59
|
-
indent(" ") {
|
68
|
+
indent(:string => " ") {
|
60
69
|
dynamic_w_indent = timeit { puts "Indented" }
|
61
70
|
}
|
62
71
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: indented_io
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 12.3.3
|
34
34
|
type: :development
|
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:
|
40
|
+
version: 12.3.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,8 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
104
|
- !ruby/object:Gem::Version
|
105
105
|
version: '0'
|
106
106
|
requirements: []
|
107
|
-
|
108
|
-
rubygems_version: 2.7.3
|
107
|
+
rubygems_version: 3.0.8
|
109
108
|
signing_key:
|
110
109
|
specification_version: 4
|
111
110
|
summary: Print indented text
|