raka 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/token.rb ADDED
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ # convenient patterns for matching
4
+ module Pattern
5
+ WORD = '[^\s_]'
6
+ TOKEN = '(?!.*__)\w+'
7
+ ANY = '\w+'
8
+ end
9
+
10
+ # Context to preserve during the token chaining
11
+ class Context
12
+ attr_reader :ext
13
+ attr_reader :scopes
14
+
15
+ def initialize(ext, scopes = [])
16
+ @ext = ext
17
+ @scopes = scopes
18
+ end
19
+ end
20
+
21
+ # methods like _xx_ are preserved for token
22
+ def internal(name)
23
+ name.length > 1 && name.to_s.start_with?('_') && name.to_s.end_with?('_')
24
+ end
25
+
26
+ # A raka expression is a list of linked tokens. The Token
27
+ # class store current token, info of previous tokens, and context.
28
+ # It plays rule of both token and expr
29
+ class Token
30
+ attr_reader :chain
31
+
32
+ def initialize(compiler, context, chain, inline_scope)
33
+ @compiler = compiler
34
+ @context = context
35
+ @chain = chain
36
+ @inline_scope = inline_scope
37
+ end
38
+
39
+ def _captures_(target)
40
+ matched = _pattern_.match(target)
41
+ keys = matched.names.map(&:to_sym)
42
+ Hash[keys.zip(matched.captures)]
43
+ end
44
+
45
+ # rubocop:disable Style/MethodLength # long but straightforward
46
+ def _parse_output_(output)
47
+ # xxx? is for minimal match
48
+ out_pattern = %r{^((?<scope>\S+)/)?}.source
49
+ out_pattern += %r{(?<target_scope>#{@inline_scope})/}.source unless @inline_scope.nil?
50
+ out_pattern += /(?<stem>(\S+))(?<ext>\.[^\.]+)$/.source
51
+ info = Regexp.new(out_pattern).match(output)
52
+ res = Hash[info.names.zip(info.captures)]
53
+ unless info[:scope].nil?
54
+ rule_scopes = Regexp.new(_scope_pattern_).match(info[:scope]).captures
55
+ res[:rule_scopes] = rule_scopes[1..-1].reverse
56
+ end
57
+ if !@inline_scope.nil? && !info[:target_scope].nil?
58
+ segs = Regexp.new(@inline_scope).match(info[:target_scope]).captures
59
+ res[:target_scope_captures] = segs
60
+ end
61
+ name_details = /^(\S+?)__(\S+)$/.match(info[:stem])
62
+ res = if name_details
63
+ res.merge(func: name_details[1], input_stem: name_details[2])
64
+ else
65
+ res.merge(func: nil, input_stem: nil)
66
+ end
67
+ res = res.merge(captures: OpenStruct.new(_captures_(output)))
68
+ res[:name] = output
69
+ res[:output] = output
70
+ res[:output_stem] = info[:stem]
71
+ OpenStruct.new res
72
+ end
73
+ # rubocop:enable Style/MethodLength
74
+
75
+ # attach a new item to the chain
76
+ def _attach_(item)
77
+ Token.new(@compiler, @context, @chain + [item], @inline_scope)
78
+ end
79
+
80
+ # rubocop:disable Style/MissingRespondToMissing # for DSL not essential
81
+ def method_missing(sym, *args)
82
+ # if ends with '=' then is to compile;
83
+ # if not but has a arg then it is template token, push template;
84
+ # else is inconclusive so just push symbol
85
+ super if internal(sym)
86
+
87
+ if sym.to_s.end_with? '='
88
+ @compiler.compile(_attach_(sym.to_s.chomp('=')), args.first)
89
+ elsif !args.empty?
90
+ _attach_ args.first.to_s
91
+ else
92
+ _attach_ sym.to_s
93
+ end
94
+ end
95
+ # rubocop:enable Style/MissingRespondToMissing
96
+
97
+ # non capture matching anything
98
+ def _(*args)
99
+ if !args.empty?
100
+ _attach_ args.first.to_s
101
+ else
102
+ _attach_ Pattern::ANY
103
+ end
104
+ end
105
+
106
+ def _=(rhs)
107
+ @compiler.compile(_attach_(Pattern::ANY), rhs)
108
+ end
109
+
110
+ def _input_?
111
+ @chain.length > 1
112
+ end
113
+
114
+ def _inputs_(output, ext)
115
+ # no input
116
+ return [] if @chain.length == 1
117
+
118
+ # match the body part besides the scope (if not scoped), leading xxx__ and .ext of output
119
+ info = _parse_output_(output)
120
+ input_stem = /^\S+?__(\S+)$/.match(info.stem)[1]
121
+ auto_input = "#{input_stem}.#{ext}"
122
+ auto_input = "#{info.target_scope}/" + auto_input if info.target_scope
123
+ auto_input = "#{info.scope}/" + auto_input if info.scope
124
+ [auto_input]
125
+ end
126
+
127
+ def _scope_pattern_
128
+ '((?:(\S+)/)?' + (@context.scopes.map { |layer| "(#{layer.join('|')})" }).join('/') + ')'
129
+ end
130
+
131
+ def _pattern_
132
+ # scopes as leading
133
+ leading = !@context.scopes.empty? ? _scope_pattern_ + '/' : _scope_pattern_
134
+ leading += "(#{@inline_scope})/" unless @inline_scope.nil?
135
+ body = @chain.reverse.map { |s| "(#{s})" }.join('__')
136
+ Regexp.new('^' + leading + body + '\.' + @context.ext.to_s + '$')
137
+ end
138
+
139
+ def _template_(scope = nil)
140
+ (scope.nil? ? '' : scope + '/') + (@inline_scope.nil? ? '' : @inline_scope + '/') +
141
+ @chain.reverse.join('__') + '.' +
142
+ @context.ext.to_s
143
+ end
144
+
145
+ # These two methods indicate that this is a pattern token
146
+ def [](pattern)
147
+ symbol = @chain.pop.to_s
148
+ # if the pattern contains child pattern like percent_(\d+), we change the capture to
149
+ # named capture so that it can be captured later. The name is symbol with the index, like func0
150
+ pattern = pattern.gsub(/\(\S+?\)/).with_index { |m, i| "(?<#{symbol}#{i}>#{m})" }
151
+
152
+ # if the symbol is _, \S+ will be put in chain, it indicates not to capture,
153
+ # so just replace it with the refined pattern
154
+ if symbol == Pattern::ANY # match-everything and not bound
155
+ @chain.push pattern.to_s
156
+ else
157
+ @chain.push "(?<#{symbol}>(#{pattern}\\w*))"
158
+ end
159
+ self
160
+ end
161
+
162
+ def []=(pattern, value)
163
+ @compiler.compile(self[pattern], value)
164
+ end
165
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: raka
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.3
5
+ platform: ruby
6
+ authors:
7
+ - yarray
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-02-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 13.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 13.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rdoc
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 6.3.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 6.3.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.1.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: juwelier
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 2.1.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 2.1.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: test-unit
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.3.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.3.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.80.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.80.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: reek
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '6.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '6.0'
111
+ description: An extensible, concise and light weight DSL on Rake to automate data
112
+ processing tasks
113
+ email: '08to09@gmail.com'
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files:
117
+ - LICENSE
118
+ - README.md
119
+ files:
120
+ - LICENSE
121
+ - README.md
122
+ - VERSION
123
+ - lib/compile.rb
124
+ - lib/interface.rbs
125
+ - lib/lang/psql/impl.rb
126
+ - lib/lang/python/impl.rb
127
+ - lib/lang/r/impl.rb
128
+ - lib/lang/r/io.R
129
+ - lib/lang/shell/impl.rb
130
+ - lib/output_type.rb
131
+ - lib/protocol.rb
132
+ - lib/raka.rb
133
+ - lib/temp.json
134
+ - lib/token.rb
135
+ homepage: http://github.com/yarray/raka
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubygems_version: 3.1.2
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: Rake for data
158
+ test_files: []