Class: Token
- Inherits:
-
Object
- Object
- Token
- Defined in:
- lib/token.rb
Overview
A raka expression is a list of linked tokens. The Token class store current token, info of previous tokens, and context. It plays rule of both token and expr
Instance Attribute Summary collapse
-
#chain ⇒ Object
readonly
Returns the value of attribute chain.
Instance Method Summary collapse
-
#[](pattern) ⇒ Object
These two methods indicate that this is a pattern token.
- #[]=(pattern, value) ⇒ Object
-
#_(*args) ⇒ Object
non capture matching anything.
- #_=(rhs) ⇒ Object
-
#_attach_(item) ⇒ Object
attach a new item to the chain.
- #_captures_(target) ⇒ Object
- #_input_? ⇒ Boolean
- #_inputs_(output, ext) ⇒ Object
-
#_parse_output_(output) ⇒ Object
rubocop:disable Style/MethodLength # long but straightforward.
- #_pattern_ ⇒ Object
- #_scope_pattern_ ⇒ Object
- #_template_(scope = nil) ⇒ Object
-
#initialize(compiler, context, chain, inline_scope) ⇒ Token
constructor
A new instance of Token.
-
#method_missing(sym, *args) ⇒ Object
rubocop:disable Style/MissingRespondToMissing # for DSL not essential.
Constructor Details
#initialize(compiler, context, chain, inline_scope) ⇒ Token
Returns a new instance of Token.
32 33 34 35 36 37 |
# File 'lib/token.rb', line 32 def initialize(compiler, context, chain, inline_scope) @compiler = compiler @context = context @chain = chain @inline_scope = inline_scope end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(sym, *args) ⇒ Object
rubocop:disable Style/MissingRespondToMissing # for DSL not essential
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/token.rb', line 81 def method_missing(sym, *args) # if ends with '=' then is to compile; # if not but has a arg then it is template token, push template; # else is inconclusive so just push symbol super if internal(sym) if sym.to_s.end_with? '=' @compiler.compile(_attach_(sym.to_s.chomp('=')), args.first) elsif !args.empty? _attach_ args.first.to_s else _attach_ sym.to_s end end |
Instance Attribute Details
#chain ⇒ Object (readonly)
Returns the value of attribute chain.
30 31 32 |
# File 'lib/token.rb', line 30 def chain @chain end |
Instance Method Details
#[](pattern) ⇒ Object
These two methods indicate that this is a pattern token
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/token.rb', line 146 def [](pattern) symbol = @chain.pop.to_s # if the pattern contains child pattern like percent_(\d+), we change the capture to # named capture so that it can be captured later. The name is symbol with the index, like func0 pattern = pattern.gsub(/\(\S+?\)/).with_index { |m, i| "(?<#{symbol}#{i}>#{m})" } # if the symbol is _, \S+ will be put in chain, it indicates not to capture, # so just replace it with the refined pattern if symbol == Pattern::ANY # match-everything and not bound @chain.push pattern.to_s else @chain.push "(?<#{symbol}>(#{pattern}\\w*))" end self end |
#[]=(pattern, value) ⇒ Object
162 163 164 |
# File 'lib/token.rb', line 162 def []=(pattern, value) @compiler.compile(self[pattern], value) end |
#_(*args) ⇒ Object
non capture matching anything
98 99 100 101 102 103 104 |
# File 'lib/token.rb', line 98 def _(*args) if !args.empty? _attach_ args.first.to_s else _attach_ Pattern::ANY end end |
#_=(rhs) ⇒ Object
106 107 108 |
# File 'lib/token.rb', line 106 def _=(rhs) @compiler.compile(_attach_(Pattern::ANY), rhs) end |
#_attach_(item) ⇒ Object
attach a new item to the chain
76 77 78 |
# File 'lib/token.rb', line 76 def _attach_(item) Token.new(@compiler, @context, @chain + [item], @inline_scope) end |
#_captures_(target) ⇒ Object
39 40 41 42 43 |
# File 'lib/token.rb', line 39 def _captures_(target) matched = _pattern_.match(target) keys = matched.names.map(&:to_sym) Hash[keys.zip(matched.captures)] end |
#_input_? ⇒ Boolean
110 111 112 |
# File 'lib/token.rb', line 110 def _input_? @chain.length > 1 end |
#_inputs_(output, ext) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/token.rb', line 114 def _inputs_(output, ext) # no input return [] if @chain.length == 1 # match the body part besides the scope (if not scoped), leading xxx__ and .ext of output info = _parse_output_(output) input_stem = /^\S+?__(\S+)$/.match(info.stem)[1] auto_input = "#{input_stem}.#{ext}" auto_input = "#{info.target_scope}/" + auto_input if info.target_scope auto_input = "#{info.scope}/" + auto_input if info.scope [auto_input] end |
#_parse_output_(output) ⇒ Object
rubocop:disable Style/MethodLength # long but straightforward
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/token.rb', line 46 def _parse_output_(output) # xxx? is for minimal match out_pattern = %r{^((?<scope>\S+)/)?}.source out_pattern += %r{(?<target_scope>#{@inline_scope})/}.source unless @inline_scope.nil? out_pattern += /(?<stem>(\S+))(?<ext>\.[^\.]+)$/.source info = Regexp.new(out_pattern).match(output) res = Hash[info.names.zip(info.captures)] unless info[:scope].nil? rule_scopes = Regexp.new(_scope_pattern_).match(info[:scope]).captures res[:rule_scopes] = rule_scopes[1..-1].reverse end if !@inline_scope.nil? && !info[:target_scope].nil? segs = Regexp.new(@inline_scope).match(info[:target_scope]).captures res[:target_scope_captures] = segs end name_details = /^(\S+?)__(\S+)$/.match(info[:stem]) res = if name_details res.merge(func: name_details[1], input_stem: name_details[2]) else res.merge(func: nil, input_stem: nil) end res = res.merge(captures: OpenStruct.new(_captures_(output))) res[:name] = output res[:output] = output res[:output_stem] = info[:stem] OpenStruct.new res end |
#_pattern_ ⇒ Object
131 132 133 134 135 136 137 |
# File 'lib/token.rb', line 131 def _pattern_ # scopes as leading leading = !@context.scopes.empty? ? _scope_pattern_ + '/' : _scope_pattern_ leading += "(#{@inline_scope})/" unless @inline_scope.nil? body = @chain.reverse.map { |s| "(#{s})" }.join('__') Regexp.new('^' + leading + body + '\.' + @context.ext.to_s + '$') end |
#_scope_pattern_ ⇒ Object
127 128 129 |
# File 'lib/token.rb', line 127 def _scope_pattern_ '((?:(\S+)/)?' + (@context.scopes.map { |layer| "(#{layer.join('|')})" }).join('/') + ')' end |
#_template_(scope = nil) ⇒ Object
139 140 141 142 143 |
# File 'lib/token.rb', line 139 def _template_(scope = nil) (scope.nil? ? '' : scope + '/') + (@inline_scope.nil? ? '' : @inline_scope + '/') + @chain.reverse.join('__') + '.' + @context.ext.to_s end |