Class: Wrong::Chunk
Instance Attribute Summary collapse
-
#block ⇒ Object
readonly
Returns the value of attribute block.
-
#file ⇒ Object
readonly
Returns the value of attribute file.
-
#line_number ⇒ Object
readonly
Returns the value of attribute line_number.
Class Method Summary collapse
-
.command_exists?(command) ⇒ Boolean
Determines if a shell command exists by searching for it in ENV.
- .from_block(block, depth = 0) ⇒ Object
-
.terminal_size ⇒ Object
Returns [width, height] of terminal when detected, nil if not detected.
- .terminal_width ⇒ Object
- .terminal_width=(forced_with) ⇒ Object
Instance Method Summary collapse
- #build_sexp ⇒ Object
-
#claim ⇒ Object
The claim is the part of the assertion inside the curly braces.
- #code ⇒ Object
- #details ⇒ Object
-
#glom(source) ⇒ Object
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.
- #indent(indent, *s) ⇒ Object
- #indent_all(amount, s) ⇒ Object
-
#initialize(file, line_number, &block) ⇒ Chunk
constructor
line parameter is 1-based.
- #line_index ⇒ Object
- #location ⇒ Object
- #newline(indent) ⇒ Object
- #parts(sexp = nil) ⇒ Object
- #pretty_value(value, starting_col = 0, indent_wrapped_lines = 6, width = Chunk.terminal_width) ⇒ Object
- #read_source_file(file) ⇒ Object
- #sexp ⇒ Object
- #wrap_and_indent(indented, starting_col, indent_wrapped_lines, full_width) ⇒ Object
Constructor Details
#initialize(file, line_number, &block) ⇒ Chunk
line parameter is 1-based
43 44 45 46 47 |
# File 'lib/wrong/chunk.rb', line 43 def initialize(file, line_number, &block) @file = file @line_number = line_number.to_i @block = block end |
Instance Attribute Details
#block ⇒ Object (readonly)
Returns the value of attribute block.
40 41 42 |
# File 'lib/wrong/chunk.rb', line 40 def block @block end |
#file ⇒ Object (readonly)
Returns the value of attribute file.
40 41 42 |
# File 'lib/wrong/chunk.rb', line 40 def file @file end |
#line_number ⇒ Object (readonly)
Returns the value of attribute line_number.
40 41 42 |
# File 'lib/wrong/chunk.rb', line 40 def line_number @line_number end |
Class Method Details
.command_exists?(command) ⇒ Boolean
Determines if a shell command exists by searching for it in ENV.
294 295 296 |
# File 'lib/wrong/chunk.rb', line 294 def self.command_exists?(command) ENV['PATH'].split(File::PATH_SEPARATOR).any? {|d| File.exists? File.join(d, command) } end |
.from_block(block, depth = 0) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/wrong/chunk.rb', line 21 def self.from_block(block, depth = 0) as_proc = block.to_proc file, line = if as_proc.respond_to? :source_location # in Ruby 1.9, or with Sourcify, it reads the source location from the block as_proc.source_location else # in Ruby 1.8, it reads the source location from the call stack # # $stderr.puts "---" # $stderr.puts caller.join("\n") relevant_caller = caller[depth] # $stderr.puts "*** #{relevant_caller}" relevant_caller.split(":") end new(file, line, &block) end |
.terminal_size ⇒ Object
Returns [width, height] of terminal when detected, nil if not detected. Think of this as a simpler version of Highline’s Highline::SystemExtensions.terminal_size() Lifted from github.com/cldwalker/hirb/blob/master/lib/hirb/util.rb#L59
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/wrong/chunk.rb', line 269 def self.terminal_size @@terminal_size ||= begin if (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/) [ENV['COLUMNS'].to_i, ENV['LINES'].to_i] elsif (RUBY_PLATFORM =~ /java/ || (!STDIN.tty? && ENV['TERM'])) && command_exists?('tput') [`tput cols`.to_i, `tput lines`.to_i] elsif STDIN.tty? && command_exists?('stty') `stty size`.scan(/\d+/).map { |s| s.to_i }.reverse else nil end rescue nil end end |
.terminal_width ⇒ Object
285 286 287 |
# File 'lib/wrong/chunk.rb', line 285 def self.terminal_width (@terminal_width ||= nil) || (terminal_size && terminal_size.first) || 80 end |
.terminal_width=(forced_with) ⇒ Object
289 290 291 |
# File 'lib/wrong/chunk.rb', line 289 def self.terminal_width= forced_with @terminal_width = forced_with end |
Instance Method Details
#build_sexp ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/wrong/chunk.rb', line 61 def build_sexp sexp = begin unless @block.nil? or @block.is_a?(String) or !Object.const_defined?(:Sourcify) # first try sourcify @block.to_sexp[3] # the [3] is to strip out the "proc {" sourcify adds to everything end rescue Exception => e # sourcify failed, so fall through end # next try glomming sexp ||= glom(if @file == "(irb)" IRB.CurrentContext.all_lines else read_source_file(@file) end) end |
#claim ⇒ Object
The claim is the part of the assertion inside the curly braces. E.g. for “assert { x == 5 }” the claim is “x == 5”
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/wrong/chunk.rb', line 108 def claim sexp() 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 |
#code ⇒ Object
125 126 127 128 129 130 131 |
# File 'lib/wrong/chunk.rb', line 125 def code self.claim.to_ruby rescue => e # note: this is untested; it's to recover from when we can't locate the code = "Failed at #{file}:#{line_number} [couldn't retrieve source code due to #{e.inspect}]" raise end |
#details ⇒ Object
163 164 165 |
# File 'lib/wrong/chunk.rb', line 163 def details @details ||= build_details end |
#glom(source) ⇒ Object
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
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/wrong/chunk.rb', line 88 def glom(source) lines = source.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 |
#indent(indent, *s) ⇒ Object
235 236 237 |
# File 'lib/wrong/chunk.rb', line 235 def indent(indent, *s) "#{" " * indent}#{s.join('')}" end |
#indent_all(amount, s) ⇒ Object
243 244 245 |
# File 'lib/wrong/chunk.rb', line 243 def indent_all(amount, s) s.gsub("\n", "\n#{indent(amount)}") end |
#line_index ⇒ Object
49 50 51 |
# File 'lib/wrong/chunk.rb', line 49 def line_index @line_number - 1 end |
#location ⇒ Object
53 54 55 |
# File 'lib/wrong/chunk.rb', line 53 def location "#{@file}:#{@line_number}" end |
#newline(indent) ⇒ Object
239 240 241 |
# File 'lib/wrong/chunk.rb', line 239 def newline(indent) "\n" + self.indent(indent) end |
#parts(sexp = nil) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/wrong/chunk.rb', line 133 def parts(sexp = nil) if sexp.nil? parts(self.claim).compact.uniq else # todo: extract some of this into Sexp parts_list = [] begin unless [:arglist, :lasgn, :iter].include? sexp.first code = sexp.to_ruby.strip parts_list << code unless code == "" || parts_list.include?(code) end rescue => e puts "#{e.class}: #{e.}" puts e.backtrace.join("\n") end if sexp.first == :iter sexp.delete_at(1) # remove the method-call-sans-block subnode end sexp.each do |sub| if sub.is_a?(Sexp) parts_list += parts(sub) end end parts_list end end |
#pretty_value(value, starting_col = 0, indent_wrapped_lines = 6, width = Chunk.terminal_width) ⇒ Object
167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/wrong/chunk.rb', line 167 def pretty_value(value, starting_col = 0, indent_wrapped_lines = 6, width = Chunk.terminal_width) # inspected = value.inspect # note that if the first line overflows due to the starting column then pp won't wrap it right inspected = PP.pp(value, "", width - starting_col).chomp # this bit might be redundant with the pp call now indented = indent_all(6, inspected) if width wrap_and_indent(indented, starting_col, indent_wrapped_lines, width) else indented end end |
#read_source_file(file) ⇒ Object
79 80 81 |
# File 'lib/wrong/chunk.rb', line 79 def read_source_file(file) Config.read_here_or_higher(file) end |
#sexp ⇒ Object
57 58 59 |
# File 'lib/wrong/chunk.rb', line 57 def sexp @sexp ||= build_sexp end |
#wrap_and_indent(indented, starting_col, indent_wrapped_lines, full_width) ⇒ Object
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/wrong/chunk.rb', line 247 def wrap_and_indent(indented, starting_col, indent_wrapped_lines, full_width) first_line = true width = full_width - starting_col # the first line is essentially shorter indented.split("\n").map do |line| s = "" while line.length > width s << line[0...width] s << newline(indent_wrapped_lines) line = line[width..-1] if first_line width += starting_col - indent_wrapped_lines first_line = false end end s << line s end.join("\n") end |