4 # Stores metadata about a file. Fields stored are:
6 # * range - the character range the layer applies to
7 # * color - the color with which to highlight the piece of code
8 # * message - what to display to the user
9 # * backend - which backend generated this layer
11 # Layer data is stored and emitted in JSON format.
13 # Note that ranges are always exclusive, so always use three dots!
16 attr_accessor :range, :color, :message, :backend
18 def initialize(where, color, message, backend, file = nil)
19 @range, @color, @message, @backend = [Layer.interpret_where(where, file),
21 backend.to_s.downcase.gsub(/backend/, '')]
25 # Determines the correct range as defined by a few rules:
27 # * Numbers get interpreted as line numbers
28 # * Strings get converted into Ranges if they include '...'
29 # * Otherwise Strings are interpreted as Class#method names
30 # * Ranges pass through untouched
32 def Layer.interpret_where where, file = nil
35 Layer.line_to_char_range file, where
37 if where =~ /\.\.\./ # grabbing this from JSON strings
38 Layer.range_string_to_char_range where
40 Layer.method_to_char_range file, where
47 # Convert a line number to a character range given a file.
48 def self.line_to_char_range(file, line)
49 file = File.read(file).split("\n")
50 start = file[0 ... line - 1].join("\n").size + 2
51 (start ... start + file[line - 1].size)
54 # Basically implements the inverse of Range#to_s
55 def self.range_string_to_char_range(range)
56 (range.split('...').first.to_i ... range.split('...').last.to_i)
59 # Convert a method name to a character range given a file.
60 def self.method_to_char_range(file, method)
61 # TODO: get smart about what class the method is defined on... ugh
62 start = File.read(file) =~ Regexp.new("def .*#{method.split(/#/).last}")
63 finish = start + 5 # TODO: fix
64 (start ... finish) # we're just layering the word "def" for now
67 # Slurp up layer data from stored JSON given the original file.
68 def self.read(original_file)
69 return [] if !File.exist?(Augment.augment_path(original_file))
70 layers = JSON.parse(File.read(Augment.augment_path(original_file)))
71 layers.map!{ |l| Layer.new(l['range'], l['color'], l['message'], l['backend']) }
72 layers.sort_by{ |l| l.range.begin }.reverse
76 { 'range' => @range, 'color' => @color, 'message' => @message,
77 'backend' => @backend}.to_json