seeing_is_believing 3.6.0 → 3.6.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2191c3427344ea922d31c319fe5442b7cc548d35
4
- data.tar.gz: c9d3e073bbeb2d093a69ffbea07f287750b42f73
2
+ SHA256:
3
+ metadata.gz: abaf2ec44d75ad4ca500c71bf90128baea06be5c0bd61fef5a0de81a402fef49
4
+ data.tar.gz: b487790b90fb61b27e77fee26622c8210a0b6e435c2084205bb791bcf3e28c08
5
5
  SHA512:
6
- metadata.gz: bbfb8141efc9ca5a3ec5eaaae28588439b593911eb411305843d39d5b42ab0d670386c0934e95d2b709f90e2d5a80133637b7b6e2181ef37387530387b8caa31
7
- data.tar.gz: 37148dff2dd6e2231a1a8be45437f41160e747eef14e52f5df2bb68258ec630ffe2345ea310b47b1b432507cf9253c9c2b7dca26d59d98f0c786df4a55087ad2
6
+ metadata.gz: '03996ee758737b276089eec6037a0c999678097759fc1dac9a1a338eae62327cb5d76253e0c491ae77a7e0852edb104da629e59db1c60228c43076d100ae8215'
7
+ data.tar.gz: 915f7e561d0bcb18f863c068e72305fa445f1b4f5f9d390843478a4ddb662cf8c38af388d5cc8da5f9ddaeeba1e569ad803c5d5c5b913d92bc6642e60155484e
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  desc 'Have Bundler setup a standalone environment -- run tests in this, b/c its faster and safer'
2
2
  task :install do
3
- # Running without rubygems # http://myronmars.to/n/dev-blog/2012/03/faster-test-boot-times-with-bundler-standalone
3
+ # Running without rubygems http://myronmars.to/n/dev-blog/2012/03/faster-test-boot-times-with-bundler-standalone
4
4
  which("bundle") or sh 'gem', 'install', 'bundler', '--no-ri', '--no-rdoc'
5
5
  Dir.exist? 'bundle' or sh 'bundle', 'install', '--standalone', '--binstubs', 'bundle/bin'
6
6
  end
@@ -834,3 +834,84 @@ Feature:
834
834
  Then stdout is "1 # => 1"
835
835
  When I run "seeing_is_believing -e '1;'"
836
836
  Then stdout is "1; # => 1"
837
+
838
+
839
+ Scenario: A spy / proxy class (Issue #136)
840
+ Given the file "spy_class.rb":
841
+ """
842
+ class String
843
+ def self.===(obj)
844
+ true
845
+ end
846
+ end
847
+ class Spy < BasicObject
848
+ def method_missing(name, *args, &block)
849
+ self
850
+ end
851
+ end
852
+ Spy.new # =>
853
+ """
854
+ When I run "seeing_is_believing -x spy_class.rb"
855
+ Then stderr is empty
856
+ And the exit status is 0
857
+ And stdout includes "Spy.new # => #<Spy:"
858
+
859
+
860
+ Scenario: Refined inspect
861
+ Given the file "refined_inspect.rb":
862
+ """
863
+ module Humanize
864
+ refine Float do
865
+ def inspect
866
+ rounded = "%.2f" % self
867
+ rounded.reverse!
868
+ rounded.gsub! /(\d{3})/, '\1,'
869
+ rounded.chomp! ","
870
+ rounded.reverse!
871
+ rounded
872
+ end #
873
+ end
874
+ end
875
+ using Humanize
876
+ 12345.6789 # =>
877
+ """
878
+ When I run "seeing_is_believing refined_inspect.rb"
879
+ Then stderr is empty
880
+ And the exit status is 0
881
+ And stdout is:
882
+ """
883
+ module Humanize
884
+ refine Float do
885
+ def inspect
886
+ rounded = "%.2f" % self # => "12345.68"
887
+ rounded.reverse! # => "86.54321"
888
+ rounded.gsub! /(\d{3})/, '\1,' # => "86.543,21"
889
+ rounded.chomp! "," # => nil
890
+ rounded.reverse! # => "12,345.68"
891
+ rounded # => "12,345.68"
892
+ end #
893
+ end # => #<refinement:Float@Humanize>
894
+ end # => #<refinement:Float@Humanize>
895
+ using Humanize # => main
896
+ 12345.6789 # => 12,345.68
897
+ """
898
+ When I run "seeing_is_believing refined_inspect.rb -x"
899
+ Then stderr is empty
900
+ And the exit status is 0
901
+ Then stdout is:
902
+ """
903
+ module Humanize
904
+ refine Float do
905
+ def inspect
906
+ rounded = "%.2f" % self
907
+ rounded.reverse!
908
+ rounded.gsub! /(\d{3})/, '\1,'
909
+ rounded.chomp! ","
910
+ rounded.reverse!
911
+ rounded
912
+ end #
913
+ end
914
+ end
915
+ using Humanize
916
+ 12345.6789 # => 12,345.68
917
+ """
@@ -7,7 +7,7 @@ require 'seeing_is_believing/code'
7
7
 
8
8
  class SeeingIsBelieving
9
9
  module Binary
10
- # Based on the behaviour of xmpfilger (a binary in the rcodetools gem)
10
+ # Based on the behaviour of xmpfilter (a binary in the rcodetools gem)
11
11
  # See https://github.com/JoshCheek/seeing_is_believing/issues/44 for more details
12
12
  class AnnotateMarkedLines
13
13
  def self.map_markers_to_linenos(program, markers)
@@ -64,7 +64,7 @@ class SeeingIsBelieving
64
64
  # 79 - "# => ".length # => 4
65
65
  # ALSO: This should be configurable, b/c otherwise you have to go into the guts of `pp`
66
66
  # https://gist.github.com/JoshCheek/6472c8f334ae493f4ab1f7865e2470e5
67
- inspect = "))"
67
+ inspect = ")) { |v| v.inspect }"
68
68
  pp = ")) { |v| PP.pp v, '', 74 }"
69
69
 
70
70
  should_inspect = inspect_linenos.include? line_number
@@ -1,3 +1,7 @@
1
+ # Polyfill String#scrub on Ruby 2.0.0
2
+ require 'seeing_is_believing/compatibility'
3
+ using SeeingIsBelieving::Compatibility
4
+
1
5
  class SeeingIsBelieving
2
6
  module Binary
3
7
  # not sure I like this name, it formats comments that show results
@@ -64,12 +68,11 @@ class SeeingIsBelieving
64
68
  end
65
69
 
66
70
  def escape_non_printable(str, omissions)
67
- str.each_char
68
- .map { |char|
69
- next char if 0x20 <= char.ord # above this has a printable representation
70
- next char if omissions.include? char
71
- char.inspect[1...-1]
72
- }.join('')
71
+ str.scrub { |c| c.inspect[1...-1] }
72
+ .gsub(/[\u0000-\u0020]/) { |char|
73
+ next char if omissions.include? char
74
+ char.inspect[1...-1]
75
+ }
73
76
  end
74
77
  end
75
78
  end
@@ -0,0 +1,28 @@
1
+ class SeeingIsBelieving
2
+ module Compatibility
3
+ end
4
+ end
5
+
6
+ # Ruby 2.0.0 is soooooo painful >.<
7
+ # want to stop supporting this so bad!!
8
+ is_v2_0 = !String.instance_methods.include?(:scrub)
9
+
10
+ is_v2_0 && begin
11
+ old_verbose, $VERBOSE = $VERBOSE, nil
12
+ module SeeingIsBelieving::Compatibility
13
+ refine String do
14
+ def scrub(char=nil, &block)
15
+ char && block = lambda { |c| char }
16
+ each_char.inject("") do |new_str, char|
17
+ if char.valid_encoding?
18
+ new_str << char
19
+ else
20
+ new_str << block.call(char)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ ensure
27
+ $VERBOSE = old_verbose
28
+ end
@@ -39,7 +39,7 @@ class SeeingIsBelieving
39
39
  self.timeout_seconds = options.delete(:timeout_seconds) || 0 # 0 is the new infinity
40
40
  self.provided_input = options.delete(:provided_input) || String.new
41
41
  self.event_handler = options.delete(:event_handler) || raise(ArgumentError, "must provide an :event_handler")
42
- self.load_path_flags = (options.delete(:load_path_dirs) || []).map { |dir| ['-I', dir] }.flatten
42
+ self.load_path_flags = (options.delete(:load_path_dirs) || []).flat_map { |dir| ['-I', dir] }
43
43
  self.require_flags = (options.delete(:require_files) || ['seeing_is_believing/the_matrix']).map { |filename| ['-r', filename] }.flatten
44
44
  self.max_line_captures = (options.delete(:max_line_captures) || Float::INFINITY) # (optimization: child stops producing results at this number, even though it might make more sense for the consumer to stop emitting them)
45
45
  self.local_cwd = options.delete(:local_cwd) || false
@@ -4,6 +4,10 @@ require 'seeing_is_believing/event_stream/events'
4
4
  require 'seeing_is_believing/error'
5
5
  require 'thread'
6
6
 
7
+ # Polyfill String#scrub on Ruby 2.0.0
8
+ require 'seeing_is_believing/compatibility'
9
+ using SeeingIsBelieving::Compatibility
10
+
7
11
  class SeeingIsBelieving
8
12
  module EventStream
9
13
  class Consumer
@@ -60,15 +64,7 @@ class SeeingIsBelieving
60
64
  rescue EncodingError
61
65
  str = str.force_encoding(Encoding::UTF_8)
62
66
  end
63
- return str.scrub('�') if str.respond_to? :scrub
64
- # basically reimplement scrub, b/c it's not implemented on 2.0.0
65
- str.each_char.inject("") do |new_str, char|
66
- if char.valid_encoding?
67
- new_str << char
68
- else
69
- new_str << '�'
70
- end
71
- end
67
+ str.scrub('�')
72
68
  end
73
69
 
74
70
  def initialize(streams)
@@ -169,51 +165,51 @@ class SeeingIsBelieving
169
165
  end
170
166
  end
171
167
 
172
- def extract_token(line)
168
+ def shift_token(line)
173
169
  event_name = line[/[^ ]+/]
174
170
  line.sub!(/^\s*[^ ]+\s*/, '')
175
171
  event_name
176
172
  end
177
173
 
178
174
  # For a consideration of many different ways of passing the message, see 5633064
179
- def extract_string(line)
180
- str = Marshal.load extract_token(line).unpack('m0').first
175
+ def shift_string(line)
176
+ str = Marshal.load shift_token(line).unpack('m0').first
181
177
  Consumer.fix_encoding(str)
182
178
  end
183
179
 
184
180
  def event_for(original_line)
185
181
  line = original_line.chomp
186
- event_name = extract_token(line).intern
182
+ event_name = shift_token(line).intern
187
183
  case event_name
188
184
  when :result
189
- line_number = extract_token(line).to_i
190
- type = extract_token(line).intern
191
- inspected = extract_string(line)
185
+ line_number = shift_token(line).to_i
186
+ type = shift_token(line).intern
187
+ inspected = shift_string(line)
192
188
  Events::LineResult.new(type: type, line_number: line_number, inspected: inspected)
193
189
  when :maxed_result
194
- line_number = extract_token(line).to_i
195
- type = extract_token(line).intern
190
+ line_number = shift_token(line).to_i
191
+ type = shift_token(line).intern
196
192
  Events::ResultsTruncated.new(type: type, line_number: line_number)
197
193
  when :exception
198
194
  Events::Exception.new \
199
- line_number: extract_token(line).to_i,
200
- class_name: extract_string(line),
201
- message: extract_string(line),
202
- backtrace: extract_token(line).to_i.times.map { extract_string line }
195
+ line_number: shift_token(line).to_i,
196
+ class_name: shift_string(line),
197
+ message: shift_string(line),
198
+ backtrace: shift_token(line).to_i.times.map { shift_string line }
203
199
  when :max_line_captures
204
- token = extract_token(line)
200
+ token = shift_token(line)
205
201
  value = token =~ /infinity/i ? Float::INFINITY : token.to_i
206
202
  Events::MaxLineCaptures.new(value: value)
207
203
  when :num_lines
208
- Events::NumLines.new(value: extract_token(line).to_i)
204
+ Events::NumLines.new(value: shift_token(line).to_i)
209
205
  when :sib_version
210
- Events::SiBVersion.new(value: extract_string(line))
206
+ Events::SiBVersion.new(value: shift_string(line))
211
207
  when :ruby_version
212
- Events::RubyVersion.new(value: extract_string(line))
208
+ Events::RubyVersion.new(value: shift_string(line))
213
209
  when :filename
214
- Events::Filename.new(value: extract_string(line))
210
+ Events::Filename.new(value: shift_string(line))
215
211
  when :exec
216
- Events::Exec.new(args: extract_string(line))
212
+ Events::Exec.new(args: shift_string(line))
217
213
  else
218
214
  raise UnknownEvent, original_line.inspect
219
215
  end
@@ -49,9 +49,13 @@ class SeeingIsBelieving
49
49
  if count < max_line_captures
50
50
  begin
51
51
  if block_given?
52
- inspected = yield(value).to_str
52
+ inspected = yield(value)
53
53
  else
54
- inspected = value.inspect.to_str
54
+ inspected = value.inspect
55
+ end
56
+ unless String === inspected
57
+ inspected = inspected.to_str
58
+ raise unless String === inspected
55
59
  end
56
60
  rescue *StackErrors
57
61
  # this is necessary because SystemStackError won't show the backtrace of the method we tried to call
@@ -76,9 +80,11 @@ class SeeingIsBelieving
76
80
  # records the exception, returns the exitstatus for that exception
77
81
  def record_exception(line_number, exception)
78
82
  return exception.status if SystemExit === exception # TODO === is not in the list
79
- if !line_number && filename
80
- begin line_number = exception.backtrace.grep(/#{filename.to_s}/).first[/:\d+/][1..-1].to_i
81
- rescue NoMethodError
83
+ unless line_number
84
+ if filename
85
+ begin line_number = exception.backtrace.grep(/#{filename.to_s}/).first[/:\d+/][1..-1].to_i
86
+ rescue NoMethodError
87
+ end
82
88
  end
83
89
  end
84
90
  line_number ||= -1
@@ -1,6 +1,13 @@
1
1
  # require this before anything else, b/c it expects the world to be sane when it is loaded
2
2
  class SeeingIsBelieving
3
3
  module Safe
4
+
5
+ # Subclasses must refine before superclasses in older Rubies, otherwise
6
+ # it finds the superclass method and behaves unexpectedly.
7
+ refine String.singleton_class do
8
+ alias === ===
9
+ end
10
+
4
11
  refine Class do
5
12
  alias === ===
6
13
  end
@@ -1,3 +1,3 @@
1
1
  class SeeingIsBelieving
2
- VERSION = '3.6.0'
2
+ VERSION = '3.6.1'
3
3
  end
@@ -9,7 +9,7 @@ class SeeingIsBelieving
9
9
  "$SiB.record_result(:inspect, #{line_number}, ("
10
10
  },
11
11
  after_each: -> line_number {
12
- "))"
12
+ ")) { |v| v.inspect }"
13
13
  }
14
14
  end
15
15
  end
@@ -60,7 +60,10 @@ RSpec.describe SeeingIsBelieving::Binary::FormatComment do
60
60
 
61
61
  def assert_printed(c, printed)
62
62
  c = c.force_encoding 'utf-8'
63
- expect(result_for 0, '', c).to eq printed
63
+ result = result_for 0, '', c
64
+ expect(result).to eq printed
65
+ expect(result.encoding).to eq Encoding::UTF_8
66
+ expect(result).to be_valid_encoding
64
67
  end
65
68
 
66
69
  it 'escapes any non-printable characters' do
@@ -192,6 +195,7 @@ RSpec.describe SeeingIsBelieving::Binary::FormatComment do
192
195
  assert_printed 124.chr , "|"
193
196
  assert_printed 125.chr , "}"
194
197
  assert_printed 126.chr , "~"
198
+ assert_printed 127.chr, "\u007F"
195
199
  end
196
200
 
197
201
  it 'can be given a list of characters to not escape' do
@@ -437,6 +437,13 @@ module SeeingIsBelieving::EventStream
437
437
  end
438
438
  end
439
439
 
440
+ it 'works with objects whose boolean inquiries have been messed with (#131)' do
441
+ exception = begin; raise; rescue; $!; end
442
+ bad_bool = Object.new
443
+ def bad_bool.!(*) raise; end
444
+ producer.record_exception bad_bool, exception # should not explode
445
+ end
446
+
440
447
  context 'recorded line number | line num is provided | it knows the file | exception comes from within file' do
441
448
  let(:exception) { begin; raise "zomg"; rescue; $!; end }
442
449
  let(:linenum) { __LINE__ - 1 }
@@ -531,6 +531,13 @@ RSpec.describe SeeingIsBelieving do
531
531
  expect(result.exception.message).to match /recursive/i
532
532
  end
533
533
 
534
+ it 'does not blow up when returning an object that recursively responds to everything' do
535
+ result = invoke('obj = BasicObject.new
536
+ def obj.method_missing(*) self; end
537
+ obj')
538
+ expect(result[3][0]).to start_with '#<BasicObject:'
539
+ end
540
+
534
541
  it 'does not blow up when the first line looks like it might have a magic comment in it (#126)' do
535
542
  expect(values_for "1+1 # and a comment with 'Accept-Encoding: gzip' in it").to eq [['2']]
536
543
  end
@@ -547,6 +554,25 @@ RSpec.describe SeeingIsBelieving do
547
554
  expect(values_for 'o = BasicObject.new; def o.inspect; "some obj"; end; o').to eq [['some obj']]
548
555
  end
549
556
 
557
+ it 'sees refined inspect (#128)' do
558
+ result = invoke <<-RUBY
559
+ module BinMeUp
560
+ refine Fixnum do
561
+ def inspect
562
+ "%08b" % self
563
+ end
564
+ end
565
+ end
566
+ using BinMeUp
567
+ 5
568
+ RUBY
569
+ expect(result[9]).to eq ['00000101']
570
+ end
571
+
572
+ it 'works when the exception does not have a backtrace (#134)' do
573
+
574
+ end
575
+
550
576
  it 'respects timeout, even when children do semi-ridiculous things, it cleans up children rather than orphaning them' do
551
577
  pre = Time.now
552
578
  result = invoke <<-CHILD, timeout_seconds: 0.5
@@ -783,14 +809,18 @@ RSpec.describe SeeingIsBelieving do
783
809
  end').stderr).to eq ''
784
810
  end
785
811
 
786
- specify 'when String does not have ==, to_s, inspect, to_i' do
812
+ specify 'when String does not have ==, to_s, inspect, to_i, ===' do
787
813
  expect(invoke('class String
788
814
  undef ==
789
815
  undef to_s
790
816
  undef to_str
791
817
  undef inspect
792
818
  undef to_i
793
- end').stderr).to eq ''
819
+ end
820
+ class << String
821
+ undef ===
822
+ end
823
+ ').stderr).to eq ''
794
824
  end
795
825
 
796
826
  specify 'when Fixnum does not have <, <<, next, ==, inspect, to_s' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seeing_is_believing
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Cheek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-29 00:00:00.000000000 Z
11
+ date: 2018-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -189,6 +189,7 @@ files:
189
189
  - lib/seeing_is_believing/binary/remove_annotations.rb
190
190
  - lib/seeing_is_believing/binary/rewrite_comments.rb
191
191
  - lib/seeing_is_believing/code.rb
192
+ - lib/seeing_is_believing/compatibility.rb
192
193
  - lib/seeing_is_believing/customize_pp.rb
193
194
  - lib/seeing_is_believing/debugger.rb
194
195
  - lib/seeing_is_believing/error.rb
@@ -287,7 +288,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
287
288
  version: '0'
288
289
  requirements: []
289
290
  rubyforge_project: seeing_is_believing
290
- rubygems_version: 2.5.2
291
+ rubygems_version: 2.7.6
291
292
  signing_key:
292
293
  specification_version: 4
293
294
  summary: Records results of every line of code in your file