class Ruby2JS::Serializer
Constants
- BASE64
Attributes
file_name[RW]
timestamps[R]
Public Class Methods
new()
click to toggle source
# File lib/ruby2js/serializer.rb, line 47 def initialize @sep = '; ' @nl = '' @ws = ' ' @width = 80 @indent = 0 @lines = [Line.new] @line = @lines.last @timestamps = {} @ast = nil @file_name = '' end
Public Instance Methods
+(value)
click to toggle source
# File lib/ruby2js/serializer.rb, line 296 def +(value) to_s+value end
capture(&block)
click to toggle source
capture (and remove) tokens from the output stream
# File lib/ruby2js/serializer.rb, line 206 def capture(&block) mark = output_location block.call lines = @lines.slice!(mark.first+1..-1) @line = @lines.last if lines.empty? lines = [@line.slice!(mark.last..-1)] elsif @line.length != mark.last lines.unshift @line.slice!(mark.last..-1) end lines.map(&:join).join(@ws) end
compact() { || ... }
click to toggle source
compact small expressions into a single line
# File lib/ruby2js/serializer.rb, line 239 def compact mark = output_location yield return unless @lines.length - mark.first > 1 return if @indent == 0 # survey what we have to work with, keeping track of a possible # split of the last argument or value work = [] len = 0 trail = split = nil slice = @lines[mark.first..-1] reindent(slice) slice.each_with_index do |line, index| line << "" if line.empty? if line.first.start_with? '//' len += @width # comments are a deal breaker else (work.push ' '; len += 1) if trail == line.indent and @indent > 0 len += line.map(&:length).inject(&:+) work += line if trail == @indent and line.indent == @indent split = [len, work.length, index] break if len >= @width - 10 end trail = line.indent end end if len < @width - 10 # full collapse @lines[mark.first..-1] = [Line.new(*work)] @line = @lines.last elsif split and split[0] < @width-10 if slice[split[2]].indent < slice[split[2]+1].indent # collapse all but the last argument (typically a hash or function) close = slice.pop slice[-1].push(*close) @lines[mark.first] = Line.new(*work[0..split[1]-1]) @lines[mark.first+1..-1] = slice[split[2]+1..-1] @line = @lines.last end end end
enable_vertical_whitespace()
click to toggle source
# File lib/ruby2js/serializer.rb, line 79 def enable_vertical_whitespace @sep = ";\n" @nl = "\n" @ws = @nl @indent = 2 end
insert(mark, line)
click to toggle source
insert a line into the output
# File lib/ruby2js/serializer.rb, line 197 def insert(mark, line) if mark.last == 0 @lines.insert(mark.first, Line.new(Token.new(line.chomp, @ast))) else @lines[mark.first].insert(mark.last, Token.new(line, @ast)) end end
mtime()
click to toggle source
# File lib/ruby2js/serializer.rb, line 74 def mtime return Time.now if @timestamps.empty? return @timestamps.values.max end
output_location()
click to toggle source
current location: [line number, token number]
# File lib/ruby2js/serializer.rb, line 192 def output_location [@lines.length-1, @line.length] end
put(string)
click to toggle source
add a single token to the current line
# File lib/ruby2js/serializer.rb, line 149 def put(string) unless String === string and string.include? "\n" @line << Token.new(string, @ast) else parts = string.split("\n") first = parts.shift @line << Token.new(first, @ast) if first @lines += parts.map {|part| Line.new(Token.new(part, @ast))} @lines << Line.new if string.end_with?("\n") @line = @lines.last end end
put!(string)
click to toggle source
add a single token to the current line without checking for newline
# File lib/ruby2js/serializer.rb, line 163 def put!(string) @line << Token.new(string.gsub("\r", "\n"), @ast) end
puts(string)
click to toggle source
add a single token to the current line and then advance to next line
# File lib/ruby2js/serializer.rb, line 168 def puts(string) unless String === string and string.include? "\n" @line << Token.new(string, @ast) else put string end @line = Line.new @lines << @line end
reindent(lines)
click to toggle source
indent multi-line parameter lists, array constants, blocks
# File lib/ruby2js/serializer.rb, line 87 def reindent(lines) indent = 0 lines.each do |line| first = line.find {|token| !token.empty?} if first last = line[line.rindex {|token| !token.empty?}] if (first.start_with? '<' and line.include? '>') or (last.end_with? '>' and line.include? '<') then node = line.join[/.*?(<.*)/, 1] indent -= @indent if node.start_with? '</' line.indent = indent node = line.join[/.*(<.*)/, 1] indent += @indent unless node.include? '</' or node.include? '/>' else indent -= @indent if ')}]'.include? first[0] and indent >= @indent line.indent = indent indent += @indent if '({['.include? last[-1] end else line.indent = indent end end end
respace()
click to toggle source
add horizontal (indentation) and vertical (blank lines) whitespace
# File lib/ruby2js/serializer.rb, line 115 def respace return if @indent == 0 reindent @lines (@lines.length-3).downto(0) do |i| if \ @lines[i].length == 0 then @lines.delete i elsif \ @lines[i+1].comment? and not @lines[i].comment? and @lines[i].indent == @lines[i+1].indent then # before a comment @lines.insert i+1, Line.new elsif \ @lines[i].indent == @lines[i+1].indent and @lines[i+1].indent < @lines[i+2].indent and not @lines[i].comment? then # start of indented block @lines.insert i+1, Line.new elsif \ @lines[i].indent > @lines[i+1].indent and @lines[i+1].indent == @lines[i+2].indent and not @lines[i+2].empty? then # end of indented block @lines.insert i+2, Line.new end end end
sourcemap()
click to toggle source
# File lib/ruby2js/serializer.rb, line 350 def sourcemap respace @mappings = '' sources = [] names = [] @mark = nil @lines.each_with_index do |line, row| col = line.indent line.each do |token| if token.respond_to? :loc and token.loc pos = token.loc.expression.begin_pos buffer = token.loc.expression.source_buffer source_index = sources.index(buffer) if not source_index source_index = sources.length timestamp buffer.name sources << buffer end line = buffer.line_for_position(pos) - 1 column = buffer.column_for_position(pos) name = nil if %i{lvasgn lvar}.include? token.ast.type name = token.ast.children.first elsif %i{casgn const}.include? token.ast.type if token.ast.children.first == nil name = token.ast.children[1] end end if name index = names.find_index(name) unless index index = names.length names << name end vlq row, col, source_index, line, column, index else vlq row, col, source_index, line, column end end col += token.length end end @sourcemap = { version: 3, file: @file_name, sources: sources.map(&:name), names: names.map(&:to_s), mappings: @mappings } end
sput(string)
click to toggle source
advance to next line and then add a single token to the current line
# File lib/ruby2js/serializer.rb, line 180 def sput(string) unless String === string and string.include? "\n" @line = Line.new(Token.new(string, @ast)) @lines << @line else @line = Line.new @lines << @line put string end end
timestamp(file)
click to toggle source
# File lib/ruby2js/serializer.rb, line 63 def timestamp(file) if file @timestamps[file] = File.mtime(file) if File.exist?(file) end end
to_s()
click to toggle source
return the output as a string
# File lib/ruby2js/serializer.rb, line 286 def to_s return @str if (@str ||= nil) respace @lines.map(&:to_s).join(@nl) end
to_str()
click to toggle source
# File lib/ruby2js/serializer.rb, line 292 def to_str @str ||= to_s end
uptodate?()
click to toggle source
# File lib/ruby2js/serializer.rb, line 69 def uptodate? return false if @timestamps.empty? return @timestamps.all? {|file, mtime| File.mtime(file) == mtime} end
vlq(*mark)
click to toggle source
docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit sokra.github.io/source-map-visualization/
# File lib/ruby2js/serializer.rb, line 304 def vlq(*mark) if !@mark diffs = mark @mark = [0, 0, 0, 0, 0, 0] else if @mark[0] == mark[0] return if @mark[4] == mark[4] and @mark[3] == mark[3] @mappings += ',' unless @mappings == '' end diffs = mark.zip(@mark).map {|a,b| a-b} end while @mark[0] < mark[0] @mappings += ';' @mark[0] += 1 diffs[1] = mark[1] end @mark[0...mark.length] = mark diffs[1..-1].each do |diff| if diff < 0 data = (-diff << 1) + 1 else data = diff << 1 end if data <= 0b11111 # workaround https://github.com/opal/opal/issues/575 encoded = BASE64[data] else encoded = '' begin digit = data & 0b11111 data >>= 5 digit |= 0b100000 if data > 0 encoded += BASE64[digit] end while data > 0 end @mappings += encoded end end
wrap(open = '{', close = '}') { || ... }
click to toggle source
wrap long statements in curly braces
# File lib/ruby2js/serializer.rb, line 222 def wrap(open = '{', close = '}') puts open mark = output_location yield if \ @lines.length > mark.first+1 or @lines[mark.first-1].join.length + @line.join.length >= @width then sput close else @line = @lines[mark.first-1] @line[-1..-1] = @lines.pop end end