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
-
#file_name ⇒ Object
Returns the value of attribute file_name.
-
#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.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/ruby2js/serializer.rb', line 47 def initialize @sep = '; ' @nl = '' @ws = ' ' @width = 80 @indent = 0 @lines = [Line.new] @line = @lines.last = {} @ast = nil @file_name = '' end |
Instance Attribute Details
#file_name ⇒ Object
Returns the value of attribute file_name.
45 46 47 |
# File 'lib/ruby2js/serializer.rb', line 45 def file_name @file_name end |
#timestamps ⇒ Object (readonly)
Returns the value of attribute timestamps.
44 45 46 |
# File 'lib/ruby2js/serializer.rb', line 44 def end |
Instance Method Details
#+(value) ⇒ Object
296 297 298 |
# File 'lib/ruby2js/serializer.rb', line 296 def +(value) to_s+value end |
#capture(&block) ⇒ Object
capture (and remove) tokens from the output stream
206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# 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 ⇒ Object
compact small expressions into a single line
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 282 283 |
# 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 ⇒ Object
79 80 81 82 83 84 |
# File 'lib/ruby2js/serializer.rb', line 79 def enable_vertical_whitespace @sep = ";\n" @nl = "\n" @ws = @nl @indent = 2 end |
#insert(mark, line) ⇒ Object
insert a line into the output
197 198 199 200 201 202 203 |
# 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 ⇒ Object
74 75 76 77 |
# File 'lib/ruby2js/serializer.rb', line 74 def mtime return Time.now if .empty? return .values.max end |
#output_location ⇒ Object
current location: [line number, token number]
192 193 194 |
# File 'lib/ruby2js/serializer.rb', line 192 def output_location [@lines.length-1, @line.length] end |
#put(string) ⇒ Object
add a single token to the current line
149 150 151 152 153 154 155 156 157 158 159 160 |
# 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) ⇒ Object
add a single token to the current line without checking for newline
163 164 165 |
# File 'lib/ruby2js/serializer.rb', line 163 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
168 169 170 171 172 173 174 175 176 177 |
# 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) ⇒ Object
indent multi-line parameter lists, array constants, blocks
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# 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 ⇒ Object
add horizontal (indentation) and vertical (blank lines) whitespace
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 |
# 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 ⇒ Object
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# 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 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) ⇒ Object
advance to next line and then add a single token to the current line
180 181 182 183 184 185 186 187 188 189 |
# 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) ⇒ Object
63 64 65 66 67 |
# File 'lib/ruby2js/serializer.rb', line 63 def (file) if file [file] = File.mtime(file) if File.exist?(file) end end |
#to_s ⇒ Object
return the output as a string
286 287 288 289 290 |
# 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 ⇒ Object
292 293 294 |
# File 'lib/ruby2js/serializer.rb', line 292 def to_str @str ||= to_s end |
#uptodate? ⇒ Boolean
69 70 71 72 |
# File 'lib/ruby2js/serializer.rb', line 69 def uptodate? return false if .empty? return .all? {|file, mtime| File.mtime(file) == mtime} end |
#vlq(*mark) ⇒ Object
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 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# 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 = '}') ⇒ Object
wrap long statements in curly braces
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# 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 |