indented_io 0.7.3 → 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|