power_assert 0.1.4 → 0.2.0

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
2
  SHA1:
3
- metadata.gz: 1afb2223a3e268c8295564a49a13c7feff085da7
4
- data.tar.gz: d37fc4cfd92f123df5863ce90ed70e68da566a34
3
+ metadata.gz: 089a171012087ec11186283c05d7cd1b238d56c1
4
+ data.tar.gz: 6a970dc3416704997c85a5b8361f9481909e7658
5
5
  SHA512:
6
- metadata.gz: 72b22a8fe4dcf9905a19b22b6081af7273fdba4ddfdea9b7cca07c852ed3c6a5bfb5ab2db6042079a95e4e78f18736d0a034a7384aec170eab6ca16b32a4cfa5
7
- data.tar.gz: 4946106cb77a3f81a457a8585f63e1c58ae81a2773d9065e58dce7e95b1a422cfa549668f38b4e5e5af1e2eb064b17bfa4abe63d60fe6a8d99d7abde86e7c33e
6
+ metadata.gz: 9a26ee36c760f14be0a7d4c6ecce7fb8128e1e3834ade0f7ace29b4667885147d807d216d0bf0e95f87a59f8e9d2600c2f425091e8df581b191995d0e51ed825
7
+ data.tar.gz: 168aa6a21ba264001f63c52d1e66b56f263a4ec6593a23bad3c11e09e1f432960a8f9630e5e36c76d8efe872637bcdcc678b24ef32b3f881dc8cf3f80e5f45df
data/README.rdoc CHANGED
@@ -7,9 +7,10 @@ Power Assert for Ruby.
7
7
  * {test-unit-power_assert}[https://github.com/k-tsj/test-unit-power_assert]
8
8
  * {minitest-power_assert}[https://github.com/hsbt/minitest-power_assert]
9
9
  * {pry-power_assert}[https://github.com/yui-knk/pry-power_assert]
10
+ * {rspec-power_assert}[https://github.com/joker1007/rspec-power_assert]
10
11
  * {power_p}[https://github.com/k-tsj/power_p]
11
12
 
12
13
  == Reference
13
14
  * {Power Assert in Ruby (at RubyKaigi 2014) // Speaker Deck}[https://speakerdeck.com/k_tsj/power-assert-in-ruby]
14
15
 
15
- == Travis Build Status {<img src="https://secure.travis-ci.org/k-tsj/power_assert.png"/>}[http://travis-ci.org/k-tsj/power_assert]
16
+ == Travis Build Status {<img src="https://secure.travis-ci.org/k-tsj/power_assert.png?branch=master"/>}[http://travis-ci.org/k-tsj/power_assert]
data/Rakefile CHANGED
@@ -4,6 +4,6 @@ require "rake/testtask"
4
4
  task :default => :test
5
5
  Rake::TestTask.new do |t|
6
6
  # helper(simplecov) must be required before loading power_assert
7
- t.ruby_opts = ["-w", "-r./test/helper", "-rpower_assert"]
7
+ t.ruby_opts = ["-w", "-r./test/helper"]
8
8
  t.test_files = FileList["test/test_*.rb"]
9
9
  end
data/lib/power_assert.rb CHANGED
@@ -9,6 +9,7 @@ rescue
9
9
  end
10
10
 
11
11
  require 'power_assert/version'
12
+ require 'power_assert/enable_tracepoint_events'
12
13
  require 'ripper'
13
14
 
14
15
  module PowerAssert
@@ -21,14 +22,31 @@ module PowerAssert
21
22
  yield configuration
22
23
  end
23
24
 
24
- def start(assertion_proc, assertion_method: nil)
25
- yield Context.new(assertion_proc, assertion_method)
25
+ def start(assertion_proc_or_source, assertion_method: nil, source_binding: TOPLEVEL_BINDING)
26
+ if respond_to?(:clear_global_method_cache, true)
27
+ clear_global_method_cache
28
+ end
29
+ yield Context.new(assertion_proc_or_source, assertion_method, source_binding)
30
+ end
31
+
32
+ private
33
+
34
+ if defined?(RubyVM) and respond_to?(:using, true)
35
+ def clear_global_method_cache
36
+ class << Object.new
37
+ using Empty
38
+ end
39
+ end
26
40
  end
27
41
  end
28
42
 
29
43
  Configuration = Struct.new(:lazy_inspection)
30
44
  private_constant :Configuration
31
45
 
46
+ module Empty
47
+ end
48
+ private_constant :Empty
49
+
32
50
  class InspectedValue
33
51
  def initialize(value)
34
52
  @value = value
@@ -40,6 +58,22 @@ module PowerAssert
40
58
  end
41
59
  private_constant :InspectedValue
42
60
 
61
+ class SafeInspectable
62
+ def initialize(value)
63
+ @value = value
64
+ end
65
+
66
+ def inspect
67
+ @value.inspect
68
+ rescue NoMethodError
69
+ InspectationFailure
70
+ end
71
+ end
72
+ private_constant :SafeInspectable
73
+
74
+ class InspectationFailure; end
75
+ private_constant :InspectationFailure
76
+
43
77
  class Context
44
78
  Value = Struct.new(:name, :value, :column)
45
79
  Ident = Struct.new(:type, :name, :column)
@@ -49,26 +83,31 @@ module PowerAssert
49
83
 
50
84
  attr_reader :message_proc
51
85
 
52
- def initialize(assertion_proc, assertion_method)
86
+ def initialize(assertion_proc_or_source, assertion_method, source_binding)
87
+ if assertion_proc_or_source.kind_of?(Proc)
88
+ @assertion_proc = assertion_proc_or_source
89
+ @line = nil
90
+ else
91
+ @assertion_proc = source_binding.eval "Proc.new {#{assertion_proc_or_source}}"
92
+ @line = assertion_proc_or_source
93
+ end
53
94
  path = nil
54
95
  lineno = nil
55
- @line = nil
56
96
  methods = nil
57
97
  refs = nil
58
98
  method_ids = nil
59
99
  return_values = []
60
100
  @base_caller_length = -1
61
- @assertion_proc = assertion_proc
62
101
  @assertion_method_name = assertion_method.to_s
63
102
  @message_proc = -> {
64
103
  return nil if @base_caller_length < 0
65
- @message ||= build_assertion_message(@line || '', methods || [], return_values, refs || [], assertion_proc.binding).freeze
104
+ @message ||= build_assertion_message(@line || '', methods || [], return_values, refs || [], @assertion_proc.binding).freeze
66
105
  }
67
- @proc_local_variables = assertion_proc.binding.eval('local_variables').map(&:to_s)
106
+ @proc_local_variables = @assertion_proc.binding.eval('local_variables').map(&:to_s)
68
107
  target_thread = Thread.current
69
108
  @trace = TracePoint.new(:return, :c_return) do |tp|
70
109
  next if method_ids and ! method_ids.include?(tp.method_id)
71
- locs = tp.binding.eval('caller_locations')
110
+ locs = tp.binding.eval('::Kernel.caller_locations')
72
111
  current_diff = locs.length - @base_caller_length
73
112
  target_diff = TARGET_CALLER_DIFF[tp.event]
74
113
  is_target_bmethod = current_diff < target_diff
@@ -77,13 +116,15 @@ module PowerAssert
77
116
  unless path
78
117
  path = locs[idx].path
79
118
  lineno = locs[idx].lineno
80
- @line = open(path).each_line.drop(lineno - 1).first
119
+ @line ||= open(path).each_line.drop(lineno - 1).first
81
120
  idents = extract_idents(Ripper.sexp(@line))
82
121
  methods, refs = idents.partition {|i| i.type == :method }
83
122
  method_ids = methods.map(&:name).map(&:to_sym).uniq
84
123
  end
85
124
  if path == locs[idx].path and lineno == locs[idx].lineno
86
- val = PowerAssert.configuration.lazy_inspection ? tp.return_value : InspectedValue.new(tp.return_value.inspect)
125
+ val = PowerAssert.configuration.lazy_inspection ?
126
+ tp.return_value :
127
+ InspectedValue.new(SafeInspectable.new(tp.return_value).inspect)
87
128
  return_values << Value[tp.method_id.to_s, val, nil]
88
129
  end
89
130
  end
@@ -115,10 +156,10 @@ module PowerAssert
115
156
  ret << line.chomp
116
157
  ret << sprintf(fmt, vals.each_with_object({}) {|v, h| h[v.column.to_s.to_sym] = '|' }).chomp
117
158
  vals.each do |i|
118
- ret << sprintf(fmt,
119
- vals.each_with_object({}) do |j, h|
120
- h[j.column.to_s.to_sym] = [i.value.inspect, '|', ' '][i.column <=> j.column]
121
- end).rstrip
159
+ inspected_vals = vals.each_with_object({}) do |j, h|
160
+ h[j.column.to_s.to_sym] = [SafeInspectable.new(i.value).inspect, '|', ' '][i.column <=> j.column]
161
+ end
162
+ ret << sprintf(fmt, inspected_vals).rstrip
122
163
  end
123
164
  ret.join("\n")
124
165
  end
@@ -186,7 +227,7 @@ module PowerAssert
186
227
  when :program
187
228
  _, ((tag0, (tag1, (tag2, (tag3, mname, _)), _), (tag4, _, ss))) = sexp
188
229
  if tag0 == :method_add_block and tag1 == :method_add_arg and tag2 == :fcall and
189
- tag3 == :@ident and mname == @assertion_method_name and (tag4 == :brace_block or tag4 == :do_block)
230
+ (tag3 == :@ident or tag3 == :@const) and mname == @assertion_method_name and (tag4 == :brace_block or tag4 == :do_block)
190
231
  ss.flat_map {|s| extract_idents(s) }
191
232
  else
192
233
  _, (s, *) = sexp
@@ -254,9 +295,3 @@ module PowerAssert
254
295
  end
255
296
  private_constant :Context
256
297
  end
257
-
258
- if defined? RubyVM
259
- RubyVM::InstructionSequence.compile_option = {
260
- specialized_instruction: false
261
- }
262
- end
@@ -0,0 +1,48 @@
1
+ if defined? RubyVM
2
+ basic_classes = [
3
+ Fixnum, Float, String, Array, Hash, Bignum, Symbol, Time, Regexp
4
+ ]
5
+
6
+ basic_operators = [
7
+ :+, :-, :*, :/, :%, :==, :===, :<, :<=, :<<, :[], :[]=,
8
+ :length, :size, :empty?, :succ, :>, :>=, :!, :!=, :=~, :freeze
9
+ ]
10
+
11
+ # set redefined flag
12
+ basic_classes.each do |klass|
13
+ basic_operators.each do |bop|
14
+ if klass.public_method_defined?(bop)
15
+ klass.instance_method(bop).owner.module_eval do
16
+ public bop
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ # bypass check_cfunc
23
+ verbose = $VERBOSE
24
+ begin
25
+ $VERBOSE = nil
26
+ module PowerAssert
27
+ refine BasicObject do
28
+ def !
29
+ end
30
+
31
+ def ==
32
+ end
33
+ end
34
+
35
+ refine Module do
36
+ def ==
37
+ end
38
+ end
39
+ end
40
+ ensure
41
+ $VERBOSE = verbose
42
+ end
43
+
44
+ # disable optimization
45
+ RubyVM::InstructionSequence.compile_option = {
46
+ specialized_instruction: false
47
+ }
48
+ end
@@ -1,3 +1,3 @@
1
1
  module PowerAssert
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -6,7 +6,7 @@ require 'set'
6
6
  class TestPowerAssert < Test::Unit::TestCase
7
7
  EXTRACT_METHODS_TEST = [
8
8
  [[[:method, "c", 4], [:method, "b", 2], [:method, "d", 8], [:method, "a", 0]],
9
- 'a(b(c), d))'],
9
+ 'a(b(c), d)'],
10
10
 
11
11
  [[[:method, "a", 0], [:method, "b", 2], [:method, "d", 6], [:method, "c", 4]],
12
12
  'a.b.c(d)'],
@@ -117,14 +117,27 @@ class TestPowerAssert < Test::Unit::TestCase
117
117
 
118
118
  EXTRACT_METHODS_TEST.each_with_index do |(expect, source), idx|
119
119
  define_method("test_extract_methods_#{'%03d' % idx}") do
120
- pa = PowerAssert.const_get(:Context).new(-> { var = nil; -> { var } }.(), nil)
120
+ pa = PowerAssert.const_get(:Context).new(-> { var = nil; -> { var } }.(), nil, TOPLEVEL_BINDING)
121
121
  pa.instance_variable_set(:@line, source)
122
122
  pa.instance_variable_set(:@assertion_method_name, 'assertion_message')
123
123
  assert_equal expect, pa.send(:extract_idents, Ripper.sexp(source)).map(&:to_a), source
124
124
  end
125
125
  end
126
126
 
127
- def assertion_message(&blk)
127
+ class BasicObjectSubclass < BasicObject
128
+ def foo
129
+ "foo"
130
+ end
131
+ end
132
+
133
+ def assertion_message(source = nil, source_binding = TOPLEVEL_BINDING, &blk)
134
+ ::PowerAssert.start(source || blk, assertion_method: __callee__, source_binding: source_binding) do |pa|
135
+ pa.yield
136
+ pa.message_proc.()
137
+ end
138
+ end
139
+
140
+ def Assertion(&blk)
128
141
  ::PowerAssert.start(blk, assertion_method: __callee__) do |pa|
129
142
  pa.yield
130
143
  pa.message_proc.()
@@ -186,6 +199,24 @@ END
186
199
  assertion_message { "0".class }
187
200
 
188
201
 
202
+ assert_equal <<END.chomp,
203
+ "0".class
204
+ |
205
+ String
206
+ END
207
+ Assertion {
208
+ "0".class
209
+ }
210
+
211
+
212
+ assert_equal <<END.chomp,
213
+ Assertion { "0".class }
214
+ |
215
+ String
216
+ END
217
+ Assertion { "0".class }
218
+
219
+
189
220
  assert_equal <<END.chomp, assertion_message {
190
221
  Set.new == Set.new([0])
191
222
  | | | | |
@@ -233,6 +264,54 @@ END
233
264
  END
234
265
  bmethod
235
266
  }
267
+
268
+
269
+ assert_equal <<END.chomp,
270
+ assertion_message { BasicObjectSubclass.new.foo }
271
+ | | |
272
+ | | "foo"
273
+ | PowerAssert::InspectationFailure
274
+ TestPowerAssert::BasicObjectSubclass
275
+ END
276
+ assertion_message { BasicObjectSubclass.new.foo }
277
+
278
+
279
+ if PowerAssert.respond_to?(:clear_global_method_cache, true)
280
+ 3.times do
281
+ assert_equal <<END.chomp, assertion_message {
282
+ String == Array
283
+ | | |
284
+ | | Array
285
+ | false
286
+ String
287
+ END
288
+ String == Array
289
+ }
290
+ end
291
+ end
292
+
293
+
294
+ a = 0
295
+ @b = 1
296
+ @@c = 2
297
+ $d = 3
298
+ assert_equal <<END.chomp, assertion_message(<<END, binding)
299
+ String(a) + String(@b) + String(@@c) + String($d)
300
+ | | | | | | | | | | |
301
+ | | | | | | | | | | 3
302
+ | | | | | | | | | "3"
303
+ | | | | | | | | "0123"
304
+ | | | | | | | 2
305
+ | | | | | | "2"
306
+ | | | | | "012"
307
+ | | | | 1
308
+ | | | "1"
309
+ | | "01"
310
+ | 0
311
+ "0"
312
+ END
313
+ String(a) + String(@b) + String(@@c) + String($d)
314
+ END
236
315
  end
237
316
 
238
317
  def test_lazy_inspection
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: power_assert
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
  - Kazuki Tsujimoto
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-27 00:00:00.000000000 Z
11
+ date: 2014-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-unit
@@ -71,6 +71,7 @@ files:
71
71
  - README.rdoc
72
72
  - Rakefile
73
73
  - lib/power_assert.rb
74
+ - lib/power_assert/enable_tracepoint_events.rb
74
75
  - lib/power_assert/version.rb
75
76
  - power_assert.gemspec
76
77
  - test/helper.rb
@@ -96,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
97
  version: '0'
97
98
  requirements: []
98
99
  rubyforge_project:
99
- rubygems_version: 2.2.2
100
+ rubygems_version: 2.4.2
100
101
  signing_key:
101
102
  specification_version: 4
102
103
  summary: Power Assert for Ruby