Class: Ruby2JS::Serializer
- Inherits:
-
Object
- Object
- Ruby2JS::Serializer
- Defined in:
- lib/ruby2js/serializer.rb
Direct Known Subclasses
Constant Summary collapse
- BASE64 =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
Instance Attribute Summary collapse
-
#timestamps ⇒ Object
readonly
Returns the value of attribute timestamps.
Instance Method Summary collapse
- #+(value) ⇒ Object
-
#capture(&block) ⇒ Object
capture (and remove) tokens from the output stream.
-
#compact ⇒ Object
compact small expressions into a single line.
- #enable_vertical_whitespace ⇒ Object
-
#initialize ⇒ Serializer
constructor
A new instance of Serializer.
-
#insert(mark, line) ⇒ Object
insert a line into the output.
- #mtime ⇒ Object
-
#output_location ⇒ Object
current location: [line number, token number].
-
#put(string) ⇒ Object
add a single token to the current line.
-
#put!(string) ⇒ Object
add a single token to the current line without checking for newline.
-
#puts(string) ⇒ Object
add a single token to the current line and then advance to next line.
-
#reindent(lines) ⇒ Object
indent multi-line parameter lists, array constants, blocks.
-
#respace ⇒ Object
add horizontal (indentation) and vertical (blank lines) whitespace.
- #sourcemap ⇒ Object
-
#sput(string) ⇒ Object
advance to next line and then add a single token to the current line.
- #timestamp(file) ⇒ Object
-
#to_s ⇒ Object
return the output as a string.
- #to_str ⇒ Object
- #uptodate? ⇒ Boolean
- #vlq(*mark) ⇒ Object
-
#wrap(open = '{', close = '}') ⇒ Object
wrap long statements in curly braces.
Constructor Details
#initialize ⇒ Serializer
Returns a new instance of Serializer.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/ruby2js/serializer.rb', line 46 def initialize @sep = '; ' @nl = '' @ws = ' ' @width = 80 @indent = 0 @lines = [Line.new] @line = @lines.last @timestamps = {} @ast = nil end |
Instance Attribute Details
#timestamps ⇒ Object (readonly)
Returns the value of attribute timestamps.
44 45 46 |
# File 'lib/ruby2js/serializer.rb', line 44 def @timestamps end |
Instance Method Details
#+(value) ⇒ Object
294 295 296 |
# File 'lib/ruby2js/serializer.rb', line 294 def +(value) to_s+value end |
#capture(&block) ⇒ Object
capture (and remove) tokens from the output stream
204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/ruby2js/serializer.rb', line 204 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 ⇒ Object
compact small expressions into a single line
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/ruby2js/serializer.rb', line 237 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 ⇒ Object
77 78 79 80 81 82 |
# File 'lib/ruby2js/serializer.rb', line 77 def enable_vertical_whitespace @sep = ";\n" @nl = "\n" @ws = @nl @indent = 2 end |
#insert(mark, line) ⇒ Object
insert a line into the output
195 196 197 198 199 200 201 |
# File 'lib/ruby2js/serializer.rb', line 195 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 ⇒ Object
72 73 74 75 |
# File 'lib/ruby2js/serializer.rb', line 72 def mtime return Time.now if @timestamps.empty? return @timestamps.values.max end |
#output_location ⇒ Object
current location: [line number, token number]
190 191 192 |
# File 'lib/ruby2js/serializer.rb', line 190 def output_location [@lines.length-1, @line.length] end |
#put(string) ⇒ Object
add a single token to the current line
147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/ruby2js/serializer.rb', line 147 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) ⇒ Object
add a single token to the current line without checking for newline
161 162 163 |
# File 'lib/ruby2js/serializer.rb', line 161 def put!(string) @line << Token.new(string.gsub("\r", "\n"), @ast) end |
#puts(string) ⇒ Object
add a single token to the current line and then advance to next line
166 167 168 169 170 171 172 173 174 175 |
# File 'lib/ruby2js/serializer.rb', line 166 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) ⇒ Object
indent multi-line parameter lists, array constants, blocks
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/ruby2js/serializer.rb', line 85 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 ⇒ Object
add horizontal (indentation) and vertical (blank lines) whitespace
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 |
# File 'lib/ruby2js/serializer.rb', line 113 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 ⇒ Object
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/ruby2js/serializer.rb', line 336 def sourcemap respace @mappings = '' sources = [] @mark = [0, 0, 0, 0, 0] @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 buffer.name sources << buffer end split = buffer.source[0...pos].split("\n") vlq row, col, source_index, [split.length - 1, 0].max, split.last.to_s.length end col += token.length end end @sourcemap = { version: 3, file: @ast.loc.expression.source_buffer.name, sources: sources.map(&:name), mappings: @mappings } end |
#sput(string) ⇒ Object
advance to next line and then add a single token to the current line
178 179 180 181 182 183 184 185 186 187 |
# File 'lib/ruby2js/serializer.rb', line 178 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) ⇒ Object
61 62 63 64 65 |
# File 'lib/ruby2js/serializer.rb', line 61 def (file) if file @timestamps[file] = File.mtime(file) if File.exist?(file) end end |
#to_s ⇒ Object
return the output as a string
284 285 286 287 288 |
# File 'lib/ruby2js/serializer.rb', line 284 def to_s return @str if (@str ||= nil) respace @lines.map(&:to_s).join(@nl) end |
#to_str ⇒ Object
290 291 292 |
# File 'lib/ruby2js/serializer.rb', line 290 def to_str @str ||= to_s end |
#uptodate? ⇒ Boolean
67 68 69 70 |
# File 'lib/ruby2js/serializer.rb', line 67 def uptodate? return false if @timestamps.empty? return @timestamps.all? {|file, mtime| File.mtime(file) == mtime} end |
#vlq(*mark) ⇒ Object
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
# File 'lib/ruby2js/serializer.rb', line 301 def vlq(*mark) if @mark[0] == mark[0] return if @mark[-3..-1] == mark[-3..-1] @mappings << ',' unless @mappings == '' end while @mark[0] < mark[0] @mappings << ';' @mark[0] += 1 @mark[1] = 0 end diffs = mark.zip(@mark).map {|a,b| a-b} @mark = mark diffs[1..4].each do |diff| if diff < 0 data = (-diff << 1) + 1 else data = diff << 1 end encoded = '' begin digit = data & 0b11111 data >>= 5 digit |= 0b100000 if data > 0 encoded << BASE64[digit] end while data > 0 @mappings << encoded end end |
#wrap(open = '{', close = '}') ⇒ Object
wrap long statements in curly braces
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/ruby2js/serializer.rb', line 220 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 |