rbs 2.2.2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +4 -0
- data/.github/workflows/comments.yml +2 -2
- data/.github/workflows/ruby.yml +1 -1
- data/.gitignore +0 -1
- data/CHANGELOG.md +43 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +117 -0
- data/Rakefile +1 -1
- data/core/dir.rbs +1 -1
- data/core/enumerator.rbs +1 -1
- data/core/false_class.rbs +1 -1
- data/core/integer.rbs +4 -4
- data/core/io/wait.rbs +1 -1
- data/core/module.rbs +21 -2
- data/core/nil_class.rbs +7 -5
- data/core/object.rbs +9 -0
- data/core/trace_point.rbs +42 -3
- data/core/true_class.rbs +1 -1
- data/ext/rbs_extension/constants.c +1 -1
- data/ext/rbs_extension/extconf.rb +1 -1
- data/ext/rbs_extension/location.c +1 -1
- data/ext/rbs_extension/parser.c +4 -3
- data/ext/rbs_extension/parserstate.c +2 -2
- data/ext/rbs_extension/unescape.c +1 -1
- data/lib/rbs/ast/members.rb +2 -1
- data/lib/rbs/collection/installer.rb +4 -1
- data/lib/rbs/definition_builder/ancestor_builder.rb +4 -2
- data/lib/rbs/definition_builder/method_builder.rb +1 -1
- data/lib/rbs/definition_builder.rb +2 -2
- data/lib/rbs/environment.rb +24 -12
- data/lib/rbs/locator.rb +24 -15
- data/lib/rbs/prototype/rb.rb +17 -6
- data/lib/rbs/resolver/constant_resolver.rb +192 -0
- data/lib/rbs/resolver/type_name_resolver.rb +55 -0
- data/lib/rbs/type_name.rb +15 -0
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs.rb +2 -0
- data/schema/members.json +4 -1
- data/sig/environment.rbs +28 -21
- data/sig/environment_loader.rbs +23 -23
- data/sig/locator.rbs +2 -0
- data/sig/manifest.yaml +8 -0
- data/sig/resolver/constant_resolver.rbs +93 -0
- data/sig/resolver/context.rbs +34 -0
- data/sig/resolver/type_name_resolver.rbs +31 -0
- data/sig/typename.rbs +9 -3
- data/stdlib/bigdecimal/0/big_decimal.rbs +135 -0
- data/stdlib/erb/0/erb.rbs +237 -0
- data/stdlib/optparse/0/optparse.rbs +20 -18
- data/stdlib/prime/0/prime.rbs +115 -4
- data/stdlib/rubygems/0/version.rbs +159 -1
- data/steep/Gemfile.lock +13 -15
- metadata +10 -3
data/sig/environment_loader.rbs
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
module RBS
|
2
2
|
# EnvironmentLoader is an object to load RBS files from filesystem.
|
3
|
-
#
|
3
|
+
#
|
4
4
|
# Set up your configuration through repository and `#add` method.
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# # Set up the repository to load library RBSs from.
|
7
7
|
# repo = RBS::Repository.default
|
8
8
|
# repo.add(Pathname("vendor/rbs/gem-rbs"))
|
9
9
|
# repo.add(Pathname("vendor/rbs/internal-rbs"))
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# loader = RBS::EnvironmentLoader.new(repository: repo)
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# # Add libraries to load RBS files.
|
14
14
|
# loader.add(library: "minitest")
|
15
15
|
# loader.add(library: "rbs", version: "1.0.0")
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# # Add dirs to load RBS files from.
|
18
18
|
# loader.add(path: Pathname("sig"))
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# # Load RBSs into an environment.
|
21
21
|
# environment = RBS::Environment.new()
|
22
22
|
# loader.load(env: environment)
|
23
|
-
#
|
23
|
+
#
|
24
24
|
class EnvironmentLoader
|
25
25
|
class UnknownLibraryError < StandardError
|
26
26
|
attr_reader library: Library
|
@@ -44,37 +44,37 @@ module RBS
|
|
44
44
|
attr_reader dirs: Array[Pathname]
|
45
45
|
|
46
46
|
# The source where the RBS comes from.
|
47
|
-
#
|
47
|
+
#
|
48
48
|
# `:core` means it is part of core library.
|
49
49
|
# `Library` means it is from library.
|
50
50
|
# `Pathname` means it is loaded from a directory.
|
51
|
-
#
|
51
|
+
#
|
52
52
|
type source = :core
|
53
53
|
| Library
|
54
54
|
| Pathname
|
55
55
|
|
56
56
|
# Accepts two optional keyword arguments.
|
57
|
-
#
|
57
|
+
#
|
58
58
|
# `core_root` is the path to the directory with RBSs for core classes.
|
59
59
|
# The default value is the core library included in RBS gem. (EnvironmentLoader::DEFAULT_CORE_ROOT)
|
60
60
|
# Passing `nil` means it skips loading core class definitions.
|
61
|
-
#
|
61
|
+
#
|
62
62
|
# `repository` is the repository for library classes.
|
63
63
|
# The default value is repository only with stdlib classes. (Repository.new)
|
64
|
-
#
|
64
|
+
#
|
65
65
|
def initialize: (?core_root: Pathname?, ?repository: Repository) -> void
|
66
|
-
|
66
|
+
|
67
67
|
# Add a path or library to load RBSs from.
|
68
|
-
#
|
68
|
+
#
|
69
69
|
# `path` can be a file or a directory.
|
70
70
|
# All `.rbs` files from the given directory will be loaded.
|
71
71
|
# Specifying a file will load the file regardless the extension of the file is.
|
72
|
-
#
|
72
|
+
#
|
73
73
|
# `library` can be a name of a gem.
|
74
74
|
# Specifying `nil` to `version` will load any version available.
|
75
75
|
# It first tries to load RBS files from gem with specified version.
|
76
76
|
# If RBS files cannot be found in the gem, it tries to load RBSs from repository.
|
77
|
-
#
|
77
|
+
#
|
78
78
|
def add: (path: Pathname) -> void
|
79
79
|
| (library: String, version: String?) -> void
|
80
80
|
|
@@ -82,26 +82,26 @@ module RBS
|
|
82
82
|
def add_collection: (Collection::Config collection_config) -> void
|
83
83
|
|
84
84
|
# This is helper function to test if RBS for a library is available or not.
|
85
|
-
#
|
85
|
+
#
|
86
86
|
def has_library?: (library: String, version: String?) -> bool
|
87
87
|
|
88
88
|
# Add all declarations to environment.
|
89
|
-
#
|
89
|
+
#
|
90
90
|
# Raises `UnknownLibraryError` if RBS cannot be loaded from a library.
|
91
|
-
#
|
91
|
+
#
|
92
92
|
# Returns an array of tuples of the declaration, path to the file, and the source.
|
93
|
-
#
|
93
|
+
#
|
94
94
|
def load: (env: Environment) -> Array[[AST::Declarations::t, Pathname, source]]
|
95
95
|
|
96
96
|
# Returns a pair of spec and path for a gem with RBS.
|
97
97
|
# Returns nil if the gem is not installed, or the gem doesn't provide RBS.
|
98
|
-
#
|
98
|
+
#
|
99
99
|
def self.gem_sig_path: (String name, String? version) -> [Gem::Specification, Pathname]?
|
100
100
|
|
101
101
|
def each_decl: () { (AST::Declarations::t, Buffer, source, Pathname) -> void } -> void
|
102
|
-
|
102
|
+
|
103
103
|
def each_dir: { (source, Pathname) -> void } -> void
|
104
|
-
|
104
|
+
|
105
105
|
def each_file: (Pathname path, immediate: boolish, skip_hidden: boolish) { (Pathname) -> void } -> void
|
106
106
|
end
|
107
107
|
end
|
data/sig/locator.rbs
CHANGED
@@ -37,6 +37,8 @@ module RBS
|
|
37
37
|
|
38
38
|
def find_in_type: (Integer pos, type: Types::t, array: Array[component]) -> bool
|
39
39
|
|
40
|
+
def find_in_type_param: (Integer pos, type_param: AST::TypeParam, array: Array[component]) -> bool
|
41
|
+
|
40
42
|
def find_in_loc: (Integer pos, location: Location[untyped, untyped]?, array: Array[component]) -> bool
|
41
43
|
|
42
44
|
def test_loc: (Integer pos, location: Location[untyped, untyped]?) -> bool
|
data/sig/manifest.yaml
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module RBS
|
2
|
+
module Resolver
|
3
|
+
class ConstantResolver
|
4
|
+
# Table stores the set of immediate child constants of a module.
|
5
|
+
#
|
6
|
+
# ```rb
|
7
|
+
# table = RBS::ConstantResolver::Table.new(env)
|
8
|
+
#
|
9
|
+
# table.children(TypeName("::Object")) # -> { ... } Returns a hash of name and constants.
|
10
|
+
# table.children(TypeName("::File::PATH_SEPARATOR")) # -> nil Returns nil because the constant is not a module.
|
11
|
+
#
|
12
|
+
# table.toplevel # -> { ... } Returns a hash of top level constants.
|
13
|
+
# ```
|
14
|
+
#
|
15
|
+
# The `#toplevel` is incompatible with Ruby.
|
16
|
+
# All constants in Ruby are defined under `Object`, and they are accessed with `::` (Colon3) operator.
|
17
|
+
# RBS is different.
|
18
|
+
# `::` constants are _toplevel_ constants, and they are not defined under `::Object`.
|
19
|
+
#
|
20
|
+
# The behavior is simulated in `ConstantResolver`.
|
21
|
+
#
|
22
|
+
class Table
|
23
|
+
attr_reader children_table: Hash[TypeName, Hash[Symbol, Constant]?]
|
24
|
+
attr_reader constants_table: Hash[TypeName, Constant]
|
25
|
+
attr_reader toplevel: Hash[Symbol, Constant]
|
26
|
+
|
27
|
+
def initialize: (Environment) -> void
|
28
|
+
|
29
|
+
def constant: (TypeName constant_name) -> Constant?
|
30
|
+
|
31
|
+
# Returns a set of constants defined under `module_name`.
|
32
|
+
# Returns `nil` if there is no module with given `module_name`.
|
33
|
+
#
|
34
|
+
def children: (TypeName module_name) -> Hash[Symbol, Constant]?
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def constant_of_module: (TypeName name, Environment::ClassEntry | Environment::ModuleEntry) -> Constant
|
39
|
+
|
40
|
+
def constant_of_constant: (TypeName name, Environment::SingleEntry[TypeName, AST::Declarations::Constant]) -> Constant
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_reader builder: DefinitionBuilder
|
44
|
+
attr_reader table: Table
|
45
|
+
attr_reader context_constants_cache: Hash[context, Hash[Symbol, Constant]?]
|
46
|
+
attr_reader child_constants_cache: Hash[TypeName, Hash[Symbol, Constant]]
|
47
|
+
|
48
|
+
def initialize: (builder: DefinitionBuilder) -> void
|
49
|
+
|
50
|
+
# Resolves to `Constant` with given constant name `name` and `context`.
|
51
|
+
# Returns `nil` if the constant cannot be resolved from the context.
|
52
|
+
#
|
53
|
+
def resolve: (Symbol name, context: context) -> Constant?
|
54
|
+
|
55
|
+
# Returns the available all constants from `context`.
|
56
|
+
#
|
57
|
+
# Returns `nil` when the `context` is invalid.
|
58
|
+
def constants: (context) -> Hash[Symbol, Constant]?
|
59
|
+
|
60
|
+
# Resolves the module_name and constant name to `Constant`
|
61
|
+
#
|
62
|
+
# ```ruby
|
63
|
+
# A::B
|
64
|
+
# ^ <- module_name
|
65
|
+
# ^ <- constant_name
|
66
|
+
# ```
|
67
|
+
#
|
68
|
+
# Find the
|
69
|
+
def resolve_child: (TypeName module_name, Symbol constant_name) -> Constant?
|
70
|
+
|
71
|
+
# Returns the table of all constants accessible with `::` (colon2) operator.
|
72
|
+
#
|
73
|
+
# * The constants under the module are included.
|
74
|
+
# * The constants under the ancestor modules are included.
|
75
|
+
# * The constants under the `::Object` class are not included.
|
76
|
+
# * The top level constants are not included.
|
77
|
+
#
|
78
|
+
def children: (TypeName module_name) -> Hash[Symbol, Constant]
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def load_context_constants: (context) -> void
|
83
|
+
|
84
|
+
def load_child_constants: (TypeName) -> void
|
85
|
+
|
86
|
+
def constants_from_context: (context, constants: Hash[Symbol, Constant]) -> bool
|
87
|
+
|
88
|
+
def constants_from_ancestors: (TypeName, constants: Hash[Symbol, Constant]) -> void
|
89
|
+
|
90
|
+
def constants_itself: (context, constants: Hash[Symbol, Constant]) -> void
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RBS
|
2
|
+
module Resolver
|
3
|
+
# `context` represents the module nesting structure.
|
4
|
+
#
|
5
|
+
# - `nil` means toplevel
|
6
|
+
# - A 2-tuple represents parent and the most inner module
|
7
|
+
# - `TypeName` is for a module
|
8
|
+
# - `false` is for unknown module
|
9
|
+
#
|
10
|
+
# Note that the `TypeName` must be an absolute type name.
|
11
|
+
#
|
12
|
+
# The following Ruby code has context of `[[nil, TypeName("::Foo")], false]` where
|
13
|
+
#
|
14
|
+
# * `Foo` is a class defined in RBS file
|
15
|
+
# * `Bar` is not defined in RBS files
|
16
|
+
#
|
17
|
+
# ```ruby
|
18
|
+
# class Foo
|
19
|
+
# module Bar
|
20
|
+
# # Context here
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# ```
|
24
|
+
#
|
25
|
+
# The unknown module (`false`) appears only in Ruby code.
|
26
|
+
# RBS modules/classes are always exists (or defines new module).
|
27
|
+
# Nesting a unknown module cannot happen in RBS.
|
28
|
+
#
|
29
|
+
# In Ruby this happens when the module/class is not declared in RBS files.
|
30
|
+
#
|
31
|
+
type context = [context, TypeName | false]
|
32
|
+
| nil
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RBS
|
2
|
+
module Resolver
|
3
|
+
# TypeNameResolver resolves given relative type name to absolute type name under a module nesting context.
|
4
|
+
#
|
5
|
+
# The type name resolution doesn't take account of ancestors of modules.
|
6
|
+
# It just ignores included modules and super classes.
|
7
|
+
#
|
8
|
+
class TypeNameResolver
|
9
|
+
type query = [TypeName, context]
|
10
|
+
|
11
|
+
def initialize: (Environment) -> void
|
12
|
+
|
13
|
+
# Translates given type name to absolute type name.
|
14
|
+
# Returns `nil` if cannot find associated type name.
|
15
|
+
#
|
16
|
+
def resolve: (TypeName, context: context) -> TypeName?
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader all_names: Set[TypeName]
|
21
|
+
|
22
|
+
attr_reader cache: Hash[query, TypeName?]
|
23
|
+
|
24
|
+
def has_name?: (TypeName) -> TypeName?
|
25
|
+
|
26
|
+
def try_cache: (query) { () -> TypeName? } -> TypeName?
|
27
|
+
|
28
|
+
def resolve_in: (TypeName, context) -> TypeName?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/sig/typename.rbs
CHANGED
@@ -56,11 +56,17 @@ module RBS
|
|
56
56
|
|
57
57
|
# Returns a new type name with a namespace appended to given namespace.
|
58
58
|
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
59
|
+
# ```rb
|
60
|
+
# TypeName("Hello").with_prefix(Namespace("World")) # => World::Hello
|
61
|
+
# TypeName("Foo::Bar").with_prefix(Namespace("::Hello")) # => ::Hello::Foo::Bar
|
62
|
+
# TypeName("::A::B").with_prefix(Namespace("C")) # => ::A::B
|
63
|
+
# ```
|
62
64
|
#
|
63
65
|
def with_prefix: (Namespace namespace) -> TypeName
|
66
|
+
|
67
|
+
def +: (TypeName) -> TypeName
|
68
|
+
|
69
|
+
def split: () -> Array[Symbol]
|
64
70
|
end
|
65
71
|
end
|
66
72
|
|
@@ -1187,6 +1187,19 @@ class BigDecimal < Numeric
|
|
1187
1187
|
#
|
1188
1188
|
def zero?: () -> bool
|
1189
1189
|
|
1190
|
+
# <!--
|
1191
|
+
# rdoc-file=ext/bigdecimal/lib/bigdecimal/util.rb
|
1192
|
+
# - a.to_d -> bigdecimal
|
1193
|
+
# -->
|
1194
|
+
# Returns self.
|
1195
|
+
#
|
1196
|
+
# require 'bigdecimal/util'
|
1197
|
+
#
|
1198
|
+
# d = BigDecimal("3.14")
|
1199
|
+
# d.to_d # => 0.314e1
|
1200
|
+
#
|
1201
|
+
def to_d: () -> BigDecimal
|
1202
|
+
|
1190
1203
|
private
|
1191
1204
|
|
1192
1205
|
def initialize_copy: (self) -> self
|
@@ -1378,3 +1391,125 @@ module Kernel
|
|
1378
1391
|
#
|
1379
1392
|
def self?.BigDecimal: (real | string | BigDecimal initial, ?int digits, ?exception: bool) -> BigDecimal
|
1380
1393
|
end
|
1394
|
+
|
1395
|
+
%a{annotate:rdoc:skip}
|
1396
|
+
class Integer
|
1397
|
+
# <!--
|
1398
|
+
# rdoc-file=ext/bigdecimal/lib/bigdecimal/util.rb
|
1399
|
+
# - int.to_d -> bigdecimal
|
1400
|
+
# -->
|
1401
|
+
# Returns the value of `int` as a BigDecimal.
|
1402
|
+
#
|
1403
|
+
# require 'bigdecimal'
|
1404
|
+
# require 'bigdecimal/util'
|
1405
|
+
#
|
1406
|
+
# 42.to_d # => 0.42e2
|
1407
|
+
#
|
1408
|
+
# See also BigDecimal::new.
|
1409
|
+
#
|
1410
|
+
def to_d: () -> BigDecimal
|
1411
|
+
end
|
1412
|
+
|
1413
|
+
%a{annotate:rdoc:skip}
|
1414
|
+
class Float
|
1415
|
+
# <!--
|
1416
|
+
# rdoc-file=ext/bigdecimal/lib/bigdecimal/util.rb
|
1417
|
+
# - float.to_d -> bigdecimal
|
1418
|
+
# - float.to_d(precision) -> bigdecimal
|
1419
|
+
# -->
|
1420
|
+
# Returns the value of `float` as a BigDecimal. The `precision` parameter is
|
1421
|
+
# used to determine the number of significant digits for the result (the default
|
1422
|
+
# is Float::DIG).
|
1423
|
+
#
|
1424
|
+
# require 'bigdecimal'
|
1425
|
+
# require 'bigdecimal/util'
|
1426
|
+
#
|
1427
|
+
# 0.5.to_d # => 0.5e0
|
1428
|
+
# 1.234.to_d(2) # => 0.12e1
|
1429
|
+
#
|
1430
|
+
# See also BigDecimal::new.
|
1431
|
+
#
|
1432
|
+
def to_d: (?Integer precision) -> BigDecimal
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
%a{annotate:rdoc:skip}
|
1436
|
+
class String
|
1437
|
+
# <!--
|
1438
|
+
# rdoc-file=ext/bigdecimal/lib/bigdecimal/util.rb
|
1439
|
+
# - str.to_d -> bigdecimal
|
1440
|
+
# -->
|
1441
|
+
# Returns the result of interpreting leading characters in `str` as a
|
1442
|
+
# BigDecimal.
|
1443
|
+
#
|
1444
|
+
# require 'bigdecimal'
|
1445
|
+
# require 'bigdecimal/util'
|
1446
|
+
#
|
1447
|
+
# "0.5".to_d # => 0.5e0
|
1448
|
+
# "123.45e1".to_d # => 0.12345e4
|
1449
|
+
# "45.67 degrees".to_d # => 0.4567e2
|
1450
|
+
#
|
1451
|
+
# See also BigDecimal::new.
|
1452
|
+
#
|
1453
|
+
def to_d: () -> BigDecimal
|
1454
|
+
end
|
1455
|
+
|
1456
|
+
%a{annotate:rdoc:skip}
|
1457
|
+
class Rational
|
1458
|
+
# <!--
|
1459
|
+
# rdoc-file=ext/bigdecimal/lib/bigdecimal/util.rb
|
1460
|
+
# - rat.to_d(precision) -> bigdecimal
|
1461
|
+
# -->
|
1462
|
+
# Returns the value as a BigDecimal.
|
1463
|
+
#
|
1464
|
+
# The required `precision` parameter is used to determine the number of
|
1465
|
+
# significant digits for the result.
|
1466
|
+
#
|
1467
|
+
# require 'bigdecimal'
|
1468
|
+
# require 'bigdecimal/util'
|
1469
|
+
#
|
1470
|
+
# Rational(22, 7).to_d(3) # => 0.314e1
|
1471
|
+
#
|
1472
|
+
# See also BigDecimal::new.
|
1473
|
+
#
|
1474
|
+
def to_d: (Integer precision) -> BigDecimal
|
1475
|
+
end
|
1476
|
+
|
1477
|
+
%a{annotate:rdoc:skip}
|
1478
|
+
class Complex
|
1479
|
+
# <!--
|
1480
|
+
# rdoc-file=ext/bigdecimal/lib/bigdecimal/util.rb
|
1481
|
+
# - cmp.to_d -> bigdecimal
|
1482
|
+
# - cmp.to_d(precision) -> bigdecimal
|
1483
|
+
# -->
|
1484
|
+
# Returns the value as a BigDecimal.
|
1485
|
+
#
|
1486
|
+
# The `precision` parameter is required for a rational complex number. This
|
1487
|
+
# parameter is used to determine the number of significant digits for the
|
1488
|
+
# result.
|
1489
|
+
#
|
1490
|
+
# require 'bigdecimal'
|
1491
|
+
# require 'bigdecimal/util'
|
1492
|
+
#
|
1493
|
+
# Complex(0.1234567, 0).to_d(4) # => 0.1235e0
|
1494
|
+
# Complex(Rational(22, 7), 0).to_d(3) # => 0.314e1
|
1495
|
+
#
|
1496
|
+
# See also BigDecimal::new.
|
1497
|
+
#
|
1498
|
+
def to_d: (*untyped args) -> BigDecimal
|
1499
|
+
end
|
1500
|
+
|
1501
|
+
%a{annotate:rdoc:skip}
|
1502
|
+
class NilClass
|
1503
|
+
# <!--
|
1504
|
+
# rdoc-file=ext/bigdecimal/lib/bigdecimal/util.rb
|
1505
|
+
# - nil.to_d -> bigdecimal
|
1506
|
+
# -->
|
1507
|
+
# Returns nil represented as a BigDecimal.
|
1508
|
+
#
|
1509
|
+
# require 'bigdecimal'
|
1510
|
+
# require 'bigdecimal/util'
|
1511
|
+
#
|
1512
|
+
# nil.to_d # => 0.0
|
1513
|
+
#
|
1514
|
+
def to_d: () -> BigDecimal
|
1515
|
+
end
|
data/stdlib/erb/0/erb.rbs
CHANGED
@@ -1,3 +1,240 @@
|
|
1
|
+
# <!-- rdoc-file=lib/erb.rb -->
|
2
|
+
# # ERB -- Ruby Templating
|
3
|
+
#
|
4
|
+
# ## Introduction
|
5
|
+
#
|
6
|
+
# ERB provides an easy to use but powerful templating system for Ruby. Using
|
7
|
+
# ERB, actual Ruby code can be added to any plain text document for the purposes
|
8
|
+
# of generating document information details and/or flow control.
|
9
|
+
#
|
10
|
+
# A very simple example is this:
|
11
|
+
#
|
12
|
+
# require 'erb'
|
13
|
+
#
|
14
|
+
# x = 42
|
15
|
+
# template = ERB.new <<-EOF
|
16
|
+
# The value of x is: <%= x %>
|
17
|
+
# EOF
|
18
|
+
# puts template.result(binding)
|
19
|
+
#
|
20
|
+
# *Prints:* The value of x is: 42
|
21
|
+
#
|
22
|
+
# More complex examples are given below.
|
23
|
+
#
|
24
|
+
# ## Recognized Tags
|
25
|
+
#
|
26
|
+
# ERB recognizes certain tags in the provided template and converts them based
|
27
|
+
# on the rules below:
|
28
|
+
#
|
29
|
+
# <% Ruby code -- inline with output %>
|
30
|
+
# <%= Ruby expression -- replace with result %>
|
31
|
+
# <%# comment -- ignored -- useful in testing %> (`<% #` doesn't work. Don't use Ruby comments.)
|
32
|
+
# % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
|
33
|
+
# %% replaced with % if first thing on a line and % processing is used
|
34
|
+
# <%% or %%> -- replace with <% or %> respectively
|
35
|
+
#
|
36
|
+
# All other text is passed through ERB filtering unchanged.
|
37
|
+
#
|
38
|
+
# ## Options
|
39
|
+
#
|
40
|
+
# There are several settings you can change when you use ERB:
|
41
|
+
# * the nature of the tags that are recognized;
|
42
|
+
# * the binding used to resolve local variables in the template.
|
43
|
+
#
|
44
|
+
#
|
45
|
+
# See the ERB.new and ERB#result methods for more detail.
|
46
|
+
#
|
47
|
+
# ## Character encodings
|
48
|
+
#
|
49
|
+
# ERB (or Ruby code generated by ERB) returns a string in the same character
|
50
|
+
# encoding as the input string. When the input string has a magic comment,
|
51
|
+
# however, it returns a string in the encoding specified by the magic comment.
|
52
|
+
#
|
53
|
+
# # -*- coding: utf-8 -*-
|
54
|
+
# require 'erb'
|
55
|
+
#
|
56
|
+
# template = ERB.new <<EOF
|
57
|
+
# <%#-*- coding: Big5 -*-%>
|
58
|
+
# \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
|
59
|
+
# EOF
|
60
|
+
# puts template.result
|
61
|
+
#
|
62
|
+
# *Prints:* _*ENCODING*_ is Big5.
|
63
|
+
#
|
64
|
+
# ## Examples
|
65
|
+
#
|
66
|
+
# ### Plain Text
|
67
|
+
#
|
68
|
+
# ERB is useful for any generic templating situation. Note that in this
|
69
|
+
# example, we use the convenient "% at start of line" tag, and we quote the
|
70
|
+
# template literally with `%q{...}` to avoid trouble with the backslash.
|
71
|
+
#
|
72
|
+
# require "erb"
|
73
|
+
#
|
74
|
+
# # Create template.
|
75
|
+
# template = %q{
|
76
|
+
# From: James Edward Gray II <james@grayproductions.net>
|
77
|
+
# To: <%= to %>
|
78
|
+
# Subject: Addressing Needs
|
79
|
+
#
|
80
|
+
# <%= to[/\w+/] %>:
|
81
|
+
#
|
82
|
+
# Just wanted to send a quick note assuring that your needs are being
|
83
|
+
# addressed.
|
84
|
+
#
|
85
|
+
# I want you to know that my team will keep working on the issues,
|
86
|
+
# especially:
|
87
|
+
#
|
88
|
+
# <%# ignore numerous minor requests -- focus on priorities %>
|
89
|
+
# % priorities.each do |priority|
|
90
|
+
# * <%= priority %>
|
91
|
+
# % end
|
92
|
+
#
|
93
|
+
# Thanks for your patience.
|
94
|
+
#
|
95
|
+
# James Edward Gray II
|
96
|
+
# }.gsub(/^ /, '')
|
97
|
+
#
|
98
|
+
# message = ERB.new(template, trim_mode: "%<>")
|
99
|
+
#
|
100
|
+
# # Set up template data.
|
101
|
+
# to = "Community Spokesman <spokesman@ruby_community.org>"
|
102
|
+
# priorities = [ "Run Ruby Quiz",
|
103
|
+
# "Document Modules",
|
104
|
+
# "Answer Questions on Ruby Talk" ]
|
105
|
+
#
|
106
|
+
# # Produce result.
|
107
|
+
# email = message.result
|
108
|
+
# puts email
|
109
|
+
#
|
110
|
+
# *Generates:*
|
111
|
+
#
|
112
|
+
# From: James Edward Gray II <james@grayproductions.net>
|
113
|
+
# To: Community Spokesman <spokesman@ruby_community.org>
|
114
|
+
# Subject: Addressing Needs
|
115
|
+
#
|
116
|
+
# Community:
|
117
|
+
#
|
118
|
+
# Just wanted to send a quick note assuring that your needs are being addressed.
|
119
|
+
#
|
120
|
+
# I want you to know that my team will keep working on the issues, especially:
|
121
|
+
#
|
122
|
+
# * Run Ruby Quiz
|
123
|
+
# * Document Modules
|
124
|
+
# * Answer Questions on Ruby Talk
|
125
|
+
#
|
126
|
+
# Thanks for your patience.
|
127
|
+
#
|
128
|
+
# James Edward Gray II
|
129
|
+
#
|
130
|
+
# ### Ruby in HTML
|
131
|
+
#
|
132
|
+
# ERB is often used in `.rhtml` files (HTML with embedded Ruby). Notice the
|
133
|
+
# need in this example to provide a special binding when the template is run, so
|
134
|
+
# that the instance variables in the Product object can be resolved.
|
135
|
+
#
|
136
|
+
# require "erb"
|
137
|
+
#
|
138
|
+
# # Build template data class.
|
139
|
+
# class Product
|
140
|
+
# def initialize( code, name, desc, cost )
|
141
|
+
# @code = code
|
142
|
+
# @name = name
|
143
|
+
# @desc = desc
|
144
|
+
# @cost = cost
|
145
|
+
#
|
146
|
+
# @features = [ ]
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# def add_feature( feature )
|
150
|
+
# @features << feature
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# # Support templating of member data.
|
154
|
+
# def get_binding
|
155
|
+
# binding
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# # ...
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# # Create template.
|
162
|
+
# template = %{
|
163
|
+
# <html>
|
164
|
+
# <head><title>Ruby Toys -- <%= @name %></title></head>
|
165
|
+
# <body>
|
166
|
+
#
|
167
|
+
# <h1><%= @name %> (<%= @code %>)</h1>
|
168
|
+
# <p><%= @desc %></p>
|
169
|
+
#
|
170
|
+
# <ul>
|
171
|
+
# <% @features.each do |f| %>
|
172
|
+
# <li><b><%= f %></b></li>
|
173
|
+
# <% end %>
|
174
|
+
# </ul>
|
175
|
+
#
|
176
|
+
# <p>
|
177
|
+
# <% if @cost < 10 %>
|
178
|
+
# <b>Only <%= @cost %>!!!</b>
|
179
|
+
# <% else %>
|
180
|
+
# Call for a price, today!
|
181
|
+
# <% end %>
|
182
|
+
# </p>
|
183
|
+
#
|
184
|
+
# </body>
|
185
|
+
# </html>
|
186
|
+
# }.gsub(/^ /, '')
|
187
|
+
#
|
188
|
+
# rhtml = ERB.new(template)
|
189
|
+
#
|
190
|
+
# # Set up template data.
|
191
|
+
# toy = Product.new( "TZ-1002",
|
192
|
+
# "Rubysapien",
|
193
|
+
# "Geek's Best Friend! Responds to Ruby commands...",
|
194
|
+
# 999.95 )
|
195
|
+
# toy.add_feature("Listens for verbal commands in the Ruby language!")
|
196
|
+
# toy.add_feature("Ignores Perl, Java, and all C variants.")
|
197
|
+
# toy.add_feature("Karate-Chop Action!!!")
|
198
|
+
# toy.add_feature("Matz signature on left leg.")
|
199
|
+
# toy.add_feature("Gem studded eyes... Rubies, of course!")
|
200
|
+
#
|
201
|
+
# # Produce result.
|
202
|
+
# rhtml.run(toy.get_binding)
|
203
|
+
#
|
204
|
+
# *Generates (some blank lines removed):*
|
205
|
+
#
|
206
|
+
# <html>
|
207
|
+
# <head><title>Ruby Toys -- Rubysapien</title></head>
|
208
|
+
# <body>
|
209
|
+
#
|
210
|
+
# <h1>Rubysapien (TZ-1002)</h1>
|
211
|
+
# <p>Geek's Best Friend! Responds to Ruby commands...</p>
|
212
|
+
#
|
213
|
+
# <ul>
|
214
|
+
# <li><b>Listens for verbal commands in the Ruby language!</b></li>
|
215
|
+
# <li><b>Ignores Perl, Java, and all C variants.</b></li>
|
216
|
+
# <li><b>Karate-Chop Action!!!</b></li>
|
217
|
+
# <li><b>Matz signature on left leg.</b></li>
|
218
|
+
# <li><b>Gem studded eyes... Rubies, of course!</b></li>
|
219
|
+
# </ul>
|
220
|
+
#
|
221
|
+
# <p>
|
222
|
+
# Call for a price, today!
|
223
|
+
# </p>
|
224
|
+
#
|
225
|
+
# </body>
|
226
|
+
# </html>
|
227
|
+
#
|
228
|
+
# ## Notes
|
229
|
+
#
|
230
|
+
# There are a variety of templating solutions available in various Ruby
|
231
|
+
# projects. For example, RDoc, distributed with Ruby, uses its own template
|
232
|
+
# engine, which can be reused elsewhere.
|
233
|
+
#
|
234
|
+
# Other popular engines could be found in the corresponding
|
235
|
+
# [Category](https://www.ruby-toolbox.com/categories/template_engines) of The
|
236
|
+
# Ruby Toolbox.
|
237
|
+
#
|
1
238
|
class ERB
|
2
239
|
# <!--
|
3
240
|
# rdoc-file=lib/erb.rb
|