cute_print 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.config/cucumber.yml +1 -0
- data/.rspec +1 -0
- data/.yardopts +6 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +99 -0
- data/LICENSE +20 -0
- data/README.md +109 -0
- data/Rakefile +14 -0
- data/VERSION +1 -0
- data/basic101.gemspec +64 -0
- data/cute_print.gemspec +96 -0
- data/features/.nav +6 -0
- data/features/configuring/configure_output.feature +21 -0
- data/features/configuring/configure_position_format.feature +30 -0
- data/features/configuring/readme.md +1 -0
- data/features/configuring/reset_configuration.feature +27 -0
- data/features/inspect_call_chain.feature +39 -0
- data/features/inspect_objects/inspect.feature +29 -0
- data/features/inspect_objects/label_and_inspect.feature +16 -0
- data/features/inspect_objects/print_source_location.feature +41 -0
- data/features/inspect_objects/readme.md +1 -0
- data/features/readme.md +1 -0
- data/features/support/env.rb +9 -0
- data/features/support/helpers/example.rb +54 -0
- data/features/support/helpers/temp_dir.rb +15 -0
- data/features/support/step_definitions.rb +23 -0
- data/lib/cute_print/configure.rb +37 -0
- data/lib/cute_print/core_ext/object.rb +5 -0
- data/lib/cute_print/core_ext.rb +1 -0
- data/lib/cute_print/default_printer.rb +14 -0
- data/lib/cute_print/finds_foreign_caller.rb +19 -0
- data/lib/cute_print/mixin.rb +44 -0
- data/lib/cute_print/printer.rb +106 -0
- data/lib/cute_print/ruby_generator.rb +17 -0
- data/lib/cute_print/ruby_parser/block.rb +12 -0
- data/lib/cute_print/ruby_parser/method_call.rb +27 -0
- data/lib/cute_print/ruby_parser/parsed_code.rb +38 -0
- data/lib/cute_print/ruby_parser/wraps_sexp.rb +19 -0
- data/lib/cute_print/ruby_parser.rb +60 -0
- data/lib/cute_print/stderr_out.rb +13 -0
- data/lib/cute_print.rb +26 -0
- data/spec/cute_print_spec.rb +69 -0
- data/spec/printer_spec.rb +64 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support/captures_stderr.rb +5 -0
- data/tasks/cucumber.rake +8 -0
- data/tasks/default.rake +1 -0
- data/tasks/jeweler.rake +29 -0
- data/tasks/spec.rake +5 -0
- data/tasks/test.rake +2 -0
- data/tasks/yard.rake +3 -0
- data/test_support/captures_stderr.rb +16 -0
- data/test_support/captures_stdout.rb +16 -0
- metadata +130 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
require "rspec/expectations"
|
2
|
+
|
3
|
+
# Instead of letting cucumber load all of the .rb, we configure
|
4
|
+
# cucumber to require them (see .config/cucumber.yml).
|
5
|
+
glob = File.join(File.dirname(__FILE__), '**/*.rb')
|
6
|
+
ruby_paths = Dir[glob].sort
|
7
|
+
ruby_paths.each do |path|
|
8
|
+
require path
|
9
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative "../../../test_support/captures_stderr.rb"
|
2
|
+
require_relative "../../../test_support/captures_stdout.rb"
|
3
|
+
|
4
|
+
require_relative "temp_dir"
|
5
|
+
|
6
|
+
class Example
|
7
|
+
|
8
|
+
include CapturesStderr
|
9
|
+
include CapturesStdout
|
10
|
+
|
11
|
+
def initialize(contents, opts = {})
|
12
|
+
@contents = contents
|
13
|
+
@filename = opts.fetch(:filename, "example.rb")
|
14
|
+
@temp_dir = TempDir.new
|
15
|
+
create_file
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
@stdout = capture_stdout do
|
20
|
+
@stderr = capture_stderr do
|
21
|
+
load path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def stderr
|
27
|
+
filter_output(@stderr)
|
28
|
+
end
|
29
|
+
|
30
|
+
def stdout
|
31
|
+
filter_output(@stdout)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def create_file
|
37
|
+
File.open(path, 'w') do |file|
|
38
|
+
file.write @contents
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def path
|
43
|
+
File.join(@temp_dir.path, @filename)
|
44
|
+
end
|
45
|
+
|
46
|
+
def filter_output(output)
|
47
|
+
redact_tmp_path(output)
|
48
|
+
end
|
49
|
+
|
50
|
+
def redact_tmp_path(output)
|
51
|
+
output.sub(/\/tmp\/.*\//, "/tmp/.../")
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "../../lib/cute_print"
|
2
|
+
|
3
|
+
Before do
|
4
|
+
CutePrint.configure { |c| c.reset }
|
5
|
+
end
|
6
|
+
|
7
|
+
Given(/^a file with:$/) do |contents|
|
8
|
+
@example = Example.new(contents)
|
9
|
+
@example.run
|
10
|
+
end
|
11
|
+
|
12
|
+
Given(/^a file named "(.*?)" with:$/) do |filename, contents|
|
13
|
+
@example = Example.new(contents, :filename => filename)
|
14
|
+
@example.run
|
15
|
+
end
|
16
|
+
|
17
|
+
Then(/^stderr should be$/) do |expected|
|
18
|
+
expect(@example.stderr).to eq expected
|
19
|
+
end
|
20
|
+
|
21
|
+
Then(/^stdout should be$/) do |expected|
|
22
|
+
expect(@example.stdout).to eq expected
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module CutePrint
|
4
|
+
|
5
|
+
class Configure
|
6
|
+
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# Configure an instance of printer.
|
10
|
+
# @api private
|
11
|
+
# @param [Printer] printer
|
12
|
+
# @yield [Configure]
|
13
|
+
def initialize(printer)
|
14
|
+
@printer = printer
|
15
|
+
yield self
|
16
|
+
end
|
17
|
+
|
18
|
+
def_delegator :@printer, :set_defaults, :reset
|
19
|
+
|
20
|
+
def self.delegate_accessor(name)
|
21
|
+
def_delegator :@printer, name
|
22
|
+
def_delegator :@printer, "#{name}="
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!attribute [rw] position_format
|
26
|
+
# @return [String] The position format
|
27
|
+
# @see Printer#position_format
|
28
|
+
delegate_accessor :position_format
|
29
|
+
|
30
|
+
# @!attribute [rw] out
|
31
|
+
# @return [#puts] The file to write to
|
32
|
+
# @see Printer#out
|
33
|
+
delegate_accessor :out
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "core_ext/object"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CutePrint
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
module FindsForeignCaller
|
5
|
+
|
6
|
+
def nearest_foreign_caller
|
7
|
+
caller.find do |s|
|
8
|
+
path = s.split(":").first
|
9
|
+
!File.expand_path(path).include?(File.expand_path(lib_path))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def lib_path
|
14
|
+
File.dirname(__FILE__)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative "default_printer"
|
2
|
+
require_relative "printer"
|
3
|
+
|
4
|
+
module CutePrint
|
5
|
+
|
6
|
+
# Methods mixed into Object, and so available globally.
|
7
|
+
#
|
8
|
+
# @note The methods in this module are part of the public API, but
|
9
|
+
# the module itself is not.
|
10
|
+
|
11
|
+
module Mixin
|
12
|
+
|
13
|
+
# @see Printer#q
|
14
|
+
def q(*args, &block)
|
15
|
+
CutePrint::DefaultPrinter.printer.q(*args, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @see Printer#ql
|
19
|
+
def ql(*args, &block)
|
20
|
+
CutePrint::DefaultPrinter.printer.ql(*args, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @see Printer#qq
|
24
|
+
def qq(*args, &block)
|
25
|
+
CutePrint::DefaultPrinter.printer.qq(*args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Debug a call chain by printing self and then returning self.
|
29
|
+
# @return [Object] self
|
30
|
+
def tapq
|
31
|
+
q self
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
# Debug a call chain by printing self, with source position, and
|
36
|
+
# then returning self.
|
37
|
+
# @return [Object] self
|
38
|
+
def tapql
|
39
|
+
ql self
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require_relative "finds_foreign_caller"
|
2
|
+
require_relative "ruby_parser"
|
3
|
+
require_relative "stderr_out"
|
4
|
+
|
5
|
+
module CutePrint
|
6
|
+
class Printer
|
7
|
+
|
8
|
+
include FindsForeignCaller
|
9
|
+
|
10
|
+
DEFAULT_POSITION_FORMAT = "%<filename>s:%<line_number>d: "
|
11
|
+
|
12
|
+
# The object to write to. Defaults to $stderr.
|
13
|
+
# @return [#puts]
|
14
|
+
attr_accessor :out
|
15
|
+
|
16
|
+
# The position format. To format a position, String#% is called
|
17
|
+
# with a hash having these keys:
|
18
|
+
#
|
19
|
+
# * :path
|
20
|
+
# * :filename
|
21
|
+
# * :line_number
|
22
|
+
#
|
23
|
+
# The default format prints the filename and line number.
|
24
|
+
# @see Printer::DEFAULT_POSITION_FORMAT
|
25
|
+
# @return [String]
|
26
|
+
attr_accessor :position_format
|
27
|
+
|
28
|
+
# Create an instance. If attributes are supplied, they override
|
29
|
+
# the defaults. For example:
|
30
|
+
#
|
31
|
+
# CutePrint.new(:out => $stdout)
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
def initialize(attrs = {})
|
35
|
+
set_defaults
|
36
|
+
attrs.each { |name, value| send "#{name}=", value }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set all attributes to their defaults.
|
40
|
+
def set_defaults
|
41
|
+
@out = StderrOut.new
|
42
|
+
@position_format = DEFAULT_POSITION_FORMAT
|
43
|
+
end
|
44
|
+
|
45
|
+
# Inspect and write one or more objects.
|
46
|
+
#
|
47
|
+
# If called without a block, prints the inspected arguments, one
|
48
|
+
# on a line.
|
49
|
+
#
|
50
|
+
# If called with a block, prints the source code of the block and
|
51
|
+
# the inspected result of the block.
|
52
|
+
def q(*values, &block)
|
53
|
+
print(__method__, values, block) do |line|
|
54
|
+
@out.puts line
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Inspect and write one or more objects, with source position.
|
59
|
+
#
|
60
|
+
# If called without a block, prints the inspected arguments, one
|
61
|
+
# on a line.
|
62
|
+
#
|
63
|
+
# If called with a block, prints the source code of the block and
|
64
|
+
# the inspected result of the block.
|
65
|
+
def ql(*values, &block)
|
66
|
+
path, line_number = nearest_foreign_caller.split(":")
|
67
|
+
line_number = line_number.to_i
|
68
|
+
print(__method__, values, block) do |line|
|
69
|
+
position = format_position(path, line_number)
|
70
|
+
@out.puts "#{position}#{line}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def print(method, values, block)
|
77
|
+
if block && !values.empty?
|
78
|
+
raise ArgumentError, "arguments and block are mutually exclusive"
|
79
|
+
end
|
80
|
+
if block
|
81
|
+
ruby_parser = RubyParser.from_block(block)
|
82
|
+
parsed_code = ruby_parser.parse
|
83
|
+
method_call = parsed_code.first_call_to_method(method)
|
84
|
+
block_code = method_call.block.to_ruby
|
85
|
+
yield "%s is %s" % [
|
86
|
+
block_code,
|
87
|
+
block.call.inspect,
|
88
|
+
]
|
89
|
+
else
|
90
|
+
values.each do |value|
|
91
|
+
yield value.inspect
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def format_position(path, line_number)
|
97
|
+
position_values = {
|
98
|
+
path: path,
|
99
|
+
filename: File.basename(path),
|
100
|
+
line_number: line_number,
|
101
|
+
}
|
102
|
+
@position_format % position_values
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative "block"
|
2
|
+
require_relative "wraps_sexp"
|
3
|
+
|
4
|
+
module CutePrint
|
5
|
+
class RubyParser
|
6
|
+
|
7
|
+
# @api private
|
8
|
+
class MethodCall
|
9
|
+
|
10
|
+
include WrapsSexp
|
11
|
+
|
12
|
+
def self.call_to_method?(sexp, method_name)
|
13
|
+
call?(sexp) && sexp[1][2] == method_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.call?(sexp)
|
17
|
+
sexp[0] == :iter && sexp[1][0] == :call
|
18
|
+
end
|
19
|
+
|
20
|
+
def block
|
21
|
+
Block.new(@sexp[3])
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative "method_call"
|
2
|
+
require_relative "wraps_sexp"
|
3
|
+
|
4
|
+
module CutePrint
|
5
|
+
class RubyParser
|
6
|
+
|
7
|
+
# How this class works is cribbed this excellent code:
|
8
|
+
#
|
9
|
+
# https://github.com/sconover/wrong/blob/30475fc5ac9d0f73135d229b1b44c045156a7e7a/lib/wrong/d.rb
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
|
13
|
+
class ParsedCode
|
14
|
+
|
15
|
+
include WrapsSexp
|
16
|
+
|
17
|
+
def first_call_to_method(method_name)
|
18
|
+
MethodCall.new(method_call_node(method_name))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def method_call_node(method_name)
|
24
|
+
if MethodCall.call_to_method?(@sexp, method_name)
|
25
|
+
return @sexp
|
26
|
+
end
|
27
|
+
@sexp.each_sexp do |node|
|
28
|
+
if MethodCall.call_to_method?(node, method_name)
|
29
|
+
return node
|
30
|
+
end
|
31
|
+
end
|
32
|
+
raise "Method call not found"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "../ruby_generator"
|
2
|
+
|
3
|
+
module CutePrint
|
4
|
+
class RubyParser
|
5
|
+
|
6
|
+
# @api private
|
7
|
+
module WrapsSexp
|
8
|
+
|
9
|
+
def initialize(sexp)
|
10
|
+
@sexp = sexp
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_ruby
|
14
|
+
RubyGenerator.to_ruby(@sexp)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "ruby_parser"
|
2
|
+
|
3
|
+
require_relative "ruby_parser/parsed_code"
|
4
|
+
|
5
|
+
module CutePrint
|
6
|
+
|
7
|
+
# This class is very much cribbed from this excellent code:
|
8
|
+
#
|
9
|
+
# https://github.com/sconover/wrong/blob/30475fc5ac9d0f73135d229b1b44c045156a7e7a/lib/wrong/chunk.rb
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
|
13
|
+
class RubyParser
|
14
|
+
|
15
|
+
def self.from_block(block)
|
16
|
+
path, line_number = block.to_proc.source_location
|
17
|
+
new(path, line_number, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(path, line_number, &block)
|
21
|
+
@path = path
|
22
|
+
@line_number = line_number
|
23
|
+
@block = block
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse
|
27
|
+
@parsed ||= parse_source(read_source)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def read_source
|
33
|
+
File.read(@path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def parser
|
37
|
+
@parser ||= ::RubyParser.new
|
38
|
+
end
|
39
|
+
|
40
|
+
# Try parsing just the starting line. While that doesn't work,
|
41
|
+
# add another line and try again.
|
42
|
+
def parse_source(source)
|
43
|
+
lines = source.lines.to_a
|
44
|
+
starting_line_index = @line_number - 1
|
45
|
+
ending_line_index = starting_line_index
|
46
|
+
sexp = nil
|
47
|
+
while !sexp && ending_line_index < lines.size
|
48
|
+
begin
|
49
|
+
snippet = lines.to_a[starting_line_index..ending_line_index].join
|
50
|
+
sexp = parser.parse(snippet)
|
51
|
+
return ParsedCode.new(sexp)
|
52
|
+
rescue Racc::ParseError
|
53
|
+
ending_line_index += 1
|
54
|
+
raise if ending_line_index >= lines.size
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
data/lib/cute_print.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative "cute_print/configure"
|
2
|
+
require_relative "cute_print/core_ext"
|
3
|
+
require_relative "cute_print/default_printer"
|
4
|
+
|
5
|
+
# Like Kernel#p, only fancier. For example, this code:
|
6
|
+
#
|
7
|
+
# require 'cute_print'
|
8
|
+
# q { 1 + 2 }
|
9
|
+
#
|
10
|
+
# prints this to $stderr:
|
11
|
+
#
|
12
|
+
# (1 + 2) is 3
|
13
|
+
module CutePrint
|
14
|
+
|
15
|
+
# Configure the library. For example:
|
16
|
+
#
|
17
|
+
# CutePrint.configure do |c|
|
18
|
+
# c.out = $stdout
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# @yieldparam config [Configure]
|
22
|
+
def self.configure(&block)
|
23
|
+
Configure.new(DefaultPrinter.printer, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
require "cute_print"
|
6
|
+
|
7
|
+
# Test the library as the user uses it. The other specs test
|
8
|
+
# internals.
|
9
|
+
|
10
|
+
describe CutePrint do
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
CutePrint.configure { |c| c.reset }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#q" do
|
17
|
+
When(:stderr) do
|
18
|
+
capture_stderr do
|
19
|
+
q 123
|
20
|
+
end
|
21
|
+
end
|
22
|
+
Then { stderr == "123\n" }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#ql" do
|
26
|
+
When(:stderr) do
|
27
|
+
capture_stderr do
|
28
|
+
@location = [File.basename(__FILE__), __LINE__ + 1].join(":")
|
29
|
+
ql 123
|
30
|
+
end
|
31
|
+
end
|
32
|
+
Then { stderr == "#{@location}: 123\n" }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#tapq" do
|
36
|
+
When do
|
37
|
+
@stderr = capture_stderr do
|
38
|
+
@result = ["1", "2"].map(&:to_i).tapq.inject(:+)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
Then { @result == 3}
|
42
|
+
Then { @stderr == "[1, 2]\n" }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#tapql" do
|
46
|
+
When do
|
47
|
+
@stderr = capture_stderr do
|
48
|
+
@location = [File.basename(__FILE__), __LINE__ + 1].join(":")
|
49
|
+
@result = ["1", "2"].map(&:to_i).tapql.inject(:+)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
Then { @result == 3}
|
53
|
+
Then { @stderr == "#{@location}: [1, 2]\n" }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'configure output' do
|
57
|
+
Given(:io) { StringIO.new }
|
58
|
+
Given do
|
59
|
+
CutePrint.configure do |c|
|
60
|
+
c.out = io
|
61
|
+
end
|
62
|
+
end
|
63
|
+
When do
|
64
|
+
q 123
|
65
|
+
end
|
66
|
+
Then { io.string == "123\n" }
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
require "cute_print/printer"
|
4
|
+
|
5
|
+
module CutePrint
|
6
|
+
|
7
|
+
describe Printer do
|
8
|
+
|
9
|
+
describe "#q" do
|
10
|
+
|
11
|
+
context "single value" do
|
12
|
+
Given(:out) { StringIO.new }
|
13
|
+
Given(:printer) { Printer.new(:out => out) }
|
14
|
+
When { printer.q [1, 2] }
|
15
|
+
Then { out.string == "[1, 2]\n" }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "multiple values" do
|
19
|
+
Given(:out) { StringIO.new }
|
20
|
+
Given(:printer) { Printer.new(:out => out) }
|
21
|
+
When { printer.q 1, 2 }
|
22
|
+
Then { out.string == "1\n2\n" }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "arguments and closure" do
|
26
|
+
Given(:out) { StringIO.new }
|
27
|
+
Given(:printer) { Printer.new(:out => out) }
|
28
|
+
When(:result) { printer.q("foo") {1 + 2} }
|
29
|
+
Then { result == Failure(ArgumentError) }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "closure (one line)" do
|
33
|
+
Given(:out) { StringIO.new }
|
34
|
+
Given(:printer) { Printer.new(:out => out) }
|
35
|
+
When { printer.q {1 + 2} }
|
36
|
+
Then { out.string == "(1 + 2) is 3\n" }
|
37
|
+
end
|
38
|
+
|
39
|
+
context "closure (two lines)" do
|
40
|
+
Given(:out) { StringIO.new }
|
41
|
+
Given(:printer) { Printer.new(:out => out) }
|
42
|
+
When do
|
43
|
+
printer.q do
|
44
|
+
(1 + 2)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
Then { out.string == "(1 + 2) is 3\n" }
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#ql" do
|
53
|
+
Given(:out) { StringIO.new }
|
54
|
+
Given(:printer) { Printer.new(:out => out) }
|
55
|
+
When do
|
56
|
+
@location = [File.basename(__FILE__), __LINE__ + 1].join(":")
|
57
|
+
printer.ql [1, 2]
|
58
|
+
end
|
59
|
+
Then { out.string == "#{@location}: [1, 2]\n" }
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|