Skip to content

Commit 016887a

Browse files
committedNov 28, 2014
Document some parts of lib
1 parent 17ef41b commit 016887a

File tree

9 files changed

+181
-34
lines changed

9 files changed

+181
-34
lines changed
 

Diff for: ‎lib/opal/compiler.rb

+52-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,45 @@
44
require 'opal/nodes'
55

66
module Opal
7+
# Compile a string of ruby code into javascript.
8+
#
9+
# @example
10+
#
11+
# Opal.compile "ruby_code"
12+
# # => "string of javascript code"
13+
#
14+
# @see [Opal::Compiler.new] for compiler options
15+
#
16+
# @param source [String] ruby source
17+
# @param options [Hash] compiler options
18+
# @return [String] javascript code
19+
#
720
def self.compile(source, options = {})
821
Compiler.new(source, options).compile
922
end
1023

24+
# [Opal::Compiler] is the main class used to compile ruby to javascript code.
25+
# This class uses [Opal::Parser] to gather the sexp syntax tree for the ruby
26+
# code, and then uses [Opal::Node] to step through the sexp to generate valid
27+
# javascript.
28+
#
29+
# @example
30+
#
31+
# Opal::Compiler.new("ruby code").compile
32+
# # => "javascript code"
33+
#
34+
# @example accessing result
35+
#
36+
# compiler = Opal::Compiler.new("ruby_code")
37+
# compiler.compile
38+
# compiler.result # => "javascript code"
39+
#
40+
# @example SourceMaps
41+
#
42+
# compiler = Opal::Compiler.new("")
43+
# compiler.compile
44+
# compiler.source_map # => #<SourceMap:>
45+
#
1146
class Compiler
1247
# Generated code gets indented with two spaces on each scope
1348
INDENT = ' '
@@ -48,7 +83,11 @@ def self.compiler_option(name, default_value, options = {})
4883
# are operators compiled inline
4984
compiler_option :inline_operators, false, :as => :inline_operators?
5085

51-
attr_reader :result, :fragments
86+
# @return [String] The compiled ruby code
87+
attr_reader :result
88+
89+
# @return [Array] all [Opal::Fragment] used to produce result
90+
attr_reader :fragments
5291

5392
# Current scope
5493
attr_accessor :scope
@@ -67,6 +106,8 @@ def initialize(source, options = {})
67106
end
68107

69108
# Compile some ruby code to a string.
109+
#
110+
# @return [String] javascript code
70111
def compile
71112
@parser = Parser.new
72113

@@ -78,11 +119,20 @@ def compile
78119
@result = @fragments.map(&:code).join('')
79120
end
80121

122+
# Returns a source map that can be used in the browser to map back to
123+
# original ruby code.
124+
#
125+
# @param source_file [String] optional source_file to reference ruby source
126+
# @return [Opal::SourceMap]
81127
def source_map(source_file = nil)
82128
Opal::SourceMap.new(@fragments, source_file || self.file)
83129
end
84130

85-
# Any helpers required by this file
131+
# Any helpers required by this file. Used by [Opal::Nodes::Top] to reference
132+
# runtime helpers that are needed. These are used to minify resulting
133+
# javascript by keeping a reference to helpers used.
134+
#
135+
# @return [Set<Symbol>]
86136
def helpers
87137
@helpers ||= Set.new([:breaker, :slice])
88138
end

Diff for: ‎lib/opal/erb.rb

+22-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,33 @@
22

33
module Opal
44
module ERB
5+
# Compile ERB code into javascript.
6+
#
7+
# [Opal::ERB] can be used to compile [ERB] templates into javascript code.
8+
# This module uses the [Opal::Compiler] internally.
9+
#
10+
# Compiled templates, when run in a javascript environment, will appear
11+
# under the `Template` namespace, and can be accessed as:
12+
#
13+
# Template['template_name'] # => template instance
14+
#
15+
# @example
16+
#
17+
# source = "<div><%= @content %></div>"
18+
#
19+
# Opal::ERB.compile source, "my_template.erb"
20+
#
21+
# @param source [String] erb content
22+
# @param file_name [String] filename for reference in template
23+
# @return [String] javascript code
24+
#
525
def self.compile(source, file_name = '(erb)')
626
Compiler.new(source, file_name).compile
727
end
828

929
class Compiler
30+
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
31+
1032
def initialize(source, file_name = '(erb)')
1133
@source, @file_name, @result = source, file_name, source
1234
end
@@ -31,8 +53,6 @@ def fix_quotes(result)
3153
result.gsub '"', '\\"'
3254
end
3355

34-
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
35-
3656
def require_erb(result)
3757
'require "erb";'+result
3858
end

Diff for: ‎lib/opal/fragment.rb

+17-5
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,27 @@ module Opal
44
# it was generated. Using this sexp, when writing fragments in order, a
55
# mapping can be created of the original location => target location,
66
# aka, source-maps!
7+
#
8+
# These are generated by nodes, so will not have to create directly.
79
class Fragment
810
# String of javascript this fragment holds
11+
# @return [String]
912
attr_reader :code
1013

14+
# Create fragment with javascript code and optional original [Opal::Sexp].
15+
#
16+
# @param code [String] javascript code
17+
# @param sexp [Opal::Sexp] sexp used for creating fragment
1118
def initialize(code, sexp = nil)
1219
@code = code.to_s
1320
@sexp = sexp
1421
end
1522

16-
# In debug mode we may wish to include the original line as a comment
23+
# In debug mode we may wish to include the original line and comment in
24+
# a javascript comment.
25+
#
26+
# @deprecated
27+
#
1728
def to_code
1829
if @sexp
1930
"/*:#{@sexp.line}:#{@sexp.column}*/#{@code}"
@@ -22,18 +33,19 @@ def to_code
2233
end
2334
end
2435

25-
# debug:
26-
# alias code to_code
27-
28-
# inspect the contents of this fragment, f("fooo")
36+
# Inspect the contents of this fragment, f("fooo")
2937
def inspect
3038
"f(#{@code.inspect})"
3139
end
3240

41+
# Original line this fragment was created from
42+
# @return [Integer, nil]
3343
def line
3444
@sexp.line if @sexp
3545
end
3646

47+
# Original column this fragment was created from
48+
# @return [Integer, nil]
3749
def column
3850
@sexp.column if @sexp
3951
end

Diff for: ‎lib/opal/parser.rb

+23
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,33 @@
44
require 'opal/parser/parser_scope'
55

66
module Opal
7+
# [Parser] is used to parse a string of ruby code into a tree of [Opal::Sexp]
8+
# to represent the given ruby source code. The [Opal::Compiler] used this tree
9+
# of sexp expressions, and turns them into the resulting javascript code.
10+
#
11+
# Usually, you would want to use [Opal::Compiler] directly, but this class
12+
# can be useful for debugging the compiler, as well as building tools around
13+
# the opal compiler to view the code structure.
14+
#
15+
# Invalid ruby code will raise an exception.
16+
#
17+
# @example
18+
#
19+
# Opal::Parser.new.parse "ruby code"
20+
# # => sexp tree
21+
#
722
class Parser < Racc::Parser
823

924
attr_reader :lexer, :file, :scope
1025

26+
# Parse the given ruby source. An optional file can be given which is used
27+
# for file context for some ruby expressions (e.g. `__FILE__`).
28+
#
29+
# If the given ruby code is not valid ruby, then an error will be raised.
30+
#
31+
# @param source [String] ruby source code
32+
# @param file [String] filename for context of ruby code
33+
# @return [Opal::Sexp] sexp expression tree representing ruby code
1134
def parse(source, file = '(string)')
1235
@file = file
1336
@scopes = []

Diff for: ‎lib/opal/parser/lexer.rb

+48-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22
require 'opal/parser/keywords'
33

44
module Opal
5+
# [Opal::Lexer] is used by [Opal::Parser] to step through ruby code, and
6+
# returning tokens representing each chunk of ruby code.
7+
#
8+
# Tokens are in the form:
9+
#
10+
# [token, [value, location]]
11+
#
12+
# where `location` is in the form `[line_number, column_number]`. The location
13+
# data can be used to produce source maps in the compiler. Tokens are
14+
# generally ruby symbols, and the value will always be a string value.
15+
#
16+
# The main method used by the parser is `next_token`, which is called
17+
# repeatedly until a token of value `false` is returned, which indicated the
18+
# EOF has been reached.
19+
#
20+
# Generally this class is only used by [Opal::Parser] directly.
21+
#
522
class Lexer
623

724
STR_FUNC_ESCAPE = 0x01
@@ -31,6 +48,16 @@ class Lexer
3148
attr_accessor :yylval
3249
attr_accessor :parser
3350

51+
# Create a new instance using the given ruby code and filename for
52+
# reference.
53+
#
54+
# @example
55+
#
56+
# Opal::Lexer.new("ruby code", "my_file.rb")
57+
#
58+
# @param source [String] ruby code to lex
59+
# @param file [String] filename of given ruby code
60+
#
3461
def initialize(source, file)
3562
@lex_state = :expr_beg
3663
@cond = 0
@@ -48,6 +75,26 @@ def initialize(source, file)
4875
@start_of_lambda = nil
4976
end
5077

78+
# Returns next token from source input stream.
79+
#
80+
# Token in form:
81+
#
82+
# [token, [value, [source_line, source_column]]]
83+
#
84+
# @return [Array]
85+
#
86+
def next_token
87+
token = self.yylex
88+
value = self.yylval
89+
location = [@tok_line, @tok_column]
90+
91+
# once location is stored, ensure next token starts in correct place
92+
@tok_column = @column
93+
@tok_line = @line
94+
95+
[token, [value, location]]
96+
end
97+
5198
def has_local?(local)
5299
parser.scope.has_local?(local.to_sym)
53100
end
@@ -151,18 +198,6 @@ def line=(line)
151198
@line = @tok_line = line
152199
end
153200

154-
def next_token
155-
token = self.yylex
156-
value = self.yylval
157-
location = [@tok_line, @tok_column]
158-
159-
# once location is stored, ensure next token starts in correct place
160-
@tok_column = @column
161-
@tok_line = @line
162-
163-
[token, [value, location]]
164-
end
165-
166201
def new_strterm(func, term, paren)
167202
{ :type => :string, :func => func, :term => term, :paren => paren }
168203
end
@@ -600,6 +635,7 @@ def process_identifier(matched, cmd_start)
600635
return matched =~ /^[A-Z]/ ? :tCONSTANT : :tIDENTIFIER
601636
end
602637

638+
# Does the heavy lifting for `next_token`.
603639
def yylex
604640
@yylval = ''
605641
@space_seen = false

Diff for: ‎lib/opal/parser/parser_scope.rb

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ class ParserScope
66
attr_reader :locals
77
attr_accessor :parent
88

9+
# Create new parse scope. Valid types are :block, :class, :module, :def.
10+
#
11+
# @param type [Symbol] scope type
912
def initialize(type)
1013
@block = type == :block
1114
@locals = []

Diff for: ‎lib/opal/parser/sexp.rb

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
module Opal
2+
# [Opal::Sexp] is used to build up the syntax tree inside [Opal::Parser]. The
3+
# compiler then steps through the sexp trees to generate the javascript code.
4+
#
5+
# For example, an array of integers `[1, 2]` might be represented by:
6+
#
7+
# s(:array, s(:int, 1), s(:int, 2))
8+
#
29
class Sexp
310

411
attr_reader :array
@@ -72,4 +79,3 @@ def pretty_inspect
7279
alias to_s inspect
7380
end
7481
end
75-

Diff for: ‎lib/opal/sprockets/environment.rb

+2-10
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,12 @@
33
require 'opal/sprockets/erb'
44

55
module Opal
6-
# Proccess using Sprockets
7-
#
8-
# Opal.process('opal-jquery') # => String
6+
# @deprecated
97
def self.process asset
108
Environment.new[asset].to_s
119
end
1210

13-
# Environment is a subclass of Sprockets::Environment which already has our opal
14-
# load paths loaded. This makes it easy for stand-alone rack apps, or test runners
15-
# that have opal load paths ready to use. You can also add an existing gem's lib
16-
# directory to our load path to use real gems inside your opal environment.
17-
#
18-
# If you are running rails, then you just need opal-rails instead, which will
19-
# do this for you.
11+
# @deprecated
2012
class Environment < ::Sprockets::Environment
2113
def initialize *args
2214
warn "WARNING: Opal::Sprockets::Environment is deprecated. "\

Diff for: ‎lib/opal/util.rb

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ module Opal
22
module Util
33
extend self
44

5-
# Used for uglifying source to minify
5+
# Used for uglifying source to minify.
6+
#
7+
# Opal::Util.uglify("javascript contents")
8+
#
9+
# @param str [String] string to minify
10+
# @return [String]
611
def uglify(str)
712
uglifyjs = DigestSourceCommand.new(:uglifyjs, nil, ' (install with: "npm install -g uglify-js")')
813
uglifyjs.digest(str)
914
end
1015

11-
# Gzip code to check file size
16+
# Gzip code to check file size.
1217
def gzip(str)
1318
gzip = DigestSourceCommand.new(:gzip, '-f', ', it is required to produce the .gz version')
1419
gzip.digest(str)

0 commit comments

Comments
 (0)
Please sign in to comment.