raka 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []