Class: Wrong::Chunk

Inherits:
Object show all
Defined in:
lib/wrong/chunk.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file, line_number, block = nil) ⇒ Chunk

line parameter is 1-based



22
23
24
25
26
# File 'lib/wrong/chunk.rb', line 22

def initialize(file, line_number, block = nil)
  @file = file
  @line_number = line_number.to_i
  @block = block
end

Instance Attribute Details

#blockObject (readonly)

Returns the value of attribute block.



19
20
21
# File 'lib/wrong/chunk.rb', line 19

def block
  @block
end

#fileObject (readonly)

Returns the value of attribute file.



19
20
21
# File 'lib/wrong/chunk.rb', line 19

def file
  @file
end

#line_numberObject (readonly)

Returns the value of attribute line_number.



19
20
21
# File 'lib/wrong/chunk.rb', line 19

def line_number
  @line_number
end

Class Method Details

.from_block(block, depth = 0) ⇒ Object



8
9
10
11
12
13
14
15
16
17
# File 'lib/wrong/chunk.rb', line 8

def self.from_block(block, depth = 0)
  file, line = if block.to_proc.respond_to? :source_location
                 # in Ruby 1.9, it reads the source location from the block
                 block.to_proc.source_location
               else
                 # in Ruby 1.8, it reads the source location from the call stack
                 caller[depth].split(":")
               end
  new(file, line, block)
end

Instance Method Details

#claimObject

The claim is the part of the assertion inside the curly braces. E.g. for “assert { x == 5 }” the claim is “x == 5”



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/wrong/chunk.rb', line 61

def claim
  parse()

  if @sexp.nil?
    raise "Could not parse #{location}"
  else
    assertion = @sexp.assertion
    statement = assertion && assertion[3]
    if statement.nil?
      @sexp
#          raise "Could not find assertion in #{location}\n\t#{@chunk.strip}\n\t#{@sexp}"
    else
      statement
    end
  end
end

#codeObject



78
79
80
# File 'lib/wrong/chunk.rb', line 78

def code
  self.claim.to_ruby
end

#detailsObject



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/wrong/chunk.rb', line 106

def details
  require "wrong/rainbow" if Wrong.config[:color]
  s = ""
  parts = self.parts
  parts.shift # remove the first part, since it's the same as the code

  details = []

  if parts.size > 0
    parts.each do |part|
      begin
        value = eval(part, block.binding)
        unless part == value.inspect  # this skips literals or tautologies
          if part =~ /\n/m
            part.gsub!(/\n/, newline(2))
            part += newline(3)
          end
          value = indent_all(3, value.inspect)
          if Wrong.config[:color]
            part = part.color(:blue)
            value = value.color(:magenta)
          end
          details << indent(2, part, " is ", value)
        end
      rescue Exception => e
        raises = "raises #{e.class}"
        if Wrong.config[:color]
          part = part.color(:blue)
          raises = raises.bold.color(:red)
        end
        details << indent(2, part, " ", raises, ": ", indent_all(3, e.message))
      end
    end
  end

  details.uniq!
  if details.empty?
    ""
  else
    "\n" + details.join("\n") + "\n"
  end
  
end

#line_indexObject



28
29
30
# File 'lib/wrong/chunk.rb', line 28

def line_index
  @line_number - 1
end

#locationObject



32
33
34
# File 'lib/wrong/chunk.rb', line 32

def location
  "#{@file}:#{@line_number}"
end

#parseObject

Algorithm: try to parse the starting line if it parses OK, then we’re done! if not, then glom the next line and try again repeat until it parses or we’re out of lines



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/wrong/chunk.rb', line 41

def parse
  lines = File.read(@file).split("\n")
  @parser ||= RubyParser.new
  @chunk = nil
  c = 0
  @sexp = nil
  while @sexp.nil? && line_index + c < lines.size
    begin
      @chunk = lines[line_index..line_index+c].join("\n")
      @sexp = @parser.parse(@chunk)
    rescue Racc::ParseError => e
      # loop and try again
      c += 1
    end
  end
  @sexp
end

#parts(sexp = nil) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/wrong/chunk.rb', line 82

def parts(sexp = nil)
  if sexp.nil?
    parts(self.claim).compact.uniq
  else
    # todo: extract some of this into Sexp
    parts_list = []
    begin
      unless sexp.first == :arglist
        code = sexp.to_ruby.strip
        parts_list << code unless code == "" || parts_list.include?(code)
      end
    rescue => e
      puts "#{e.class}: #{e.message}"
      puts e.backtrace.join("\n")
    end
    sexp.each do |sub|
      if sub.is_a?(Sexp)
        parts_list += parts(sub)
      end
    end
    parts_list
  end
end