mikras_utils 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,108 @@
1
+
2
+ class Analyzer
3
+ attr_reader :spec
4
+ def vars = spec.variables
5
+
6
+ def initialize(spec)
7
+ @spec = spec
8
+ end
9
+
10
+ def analyze
11
+ interpolate
12
+ expand_rules
13
+ merge_rules
14
+ spec
15
+ end
16
+
17
+ def self.analyze(spec)
18
+ self.new(spec).analyze
19
+ end
20
+
21
+ private
22
+ #
23
+ # Interpolate variables
24
+ #
25
+ def interpolate
26
+ interpolate_variables
27
+ interpolate_spec
28
+ end
29
+
30
+ def interpolate_variables
31
+ spec.variables.transform_values! { |a|
32
+ a.map { |e|
33
+ if e =~ /^\$[A-Za-z0-9_]+$/
34
+ spec.variables[e] or ShellOpts::error "Unknown variable #{e}"
35
+ else
36
+ e
37
+ end
38
+ }.flatten
39
+ }
40
+ end
41
+
42
+ def interpolate_spec
43
+ spec.rules.each { |r| interpolate_rule(r) }
44
+ end
45
+
46
+ def interpolate_rule(rule)
47
+ rule.tables = interpolate_array(rule.tables)
48
+ p rule.opers.map(&:class)
49
+
50
+ rule.opers.each { |op| interpolate_oper(op) }
51
+ end
52
+
53
+ def interpolate_oper(oper)
54
+ oper.accesses.each { |a| interpolate_access(a) }
55
+ end
56
+
57
+ def interpolate_access(access)
58
+ access.roles = interpolate_array(access.roles)
59
+ access.tables = interpolate_string(access.tables)
60
+ access.fields = interpolate_array(access.fields)
61
+ access.where = interpolate_string(access.where)
62
+ end
63
+
64
+ def interpolate_string(string)
65
+ return nil if string.nil?
66
+ for key, value in vars
67
+ next if !value.is_a?(String)
68
+ string.gsub!(/#{key}/, value)
69
+ end
70
+ string
71
+ end
72
+
73
+ def interpolate_array(array)
74
+ return nil if array.nil?
75
+ array.map { |e| vars[e] || e }.flatten
76
+ end
77
+
78
+ #
79
+ # Expand rules
80
+ #
81
+ def expand_rules()
82
+ rules = []
83
+ spec.rules.each { |rule|
84
+ rule.tables.each { |t| r = rule.dup; r.tables = [t]; rules << r }
85
+ }
86
+ spec.rules = rules
87
+ end
88
+
89
+ #
90
+ # Merge rules
91
+ #
92
+ def merge_rules()
93
+ spec.rules = spec.rules.group_by { |rule| rule.tables.first }.map { |table, rules|
94
+ rule = Rule.new([table])
95
+ for oper in Spec::OPERS
96
+ rule[oper] = merge_opers(oper, rules.map { |r| r[oper] }.flatten)
97
+ end
98
+ rule
99
+ }
100
+ end
101
+
102
+ def merge_opers(oper, opers)
103
+ oper = Oper.new(oper)
104
+ oper.accesses = opers.map { |op| op.accesses }.flatten
105
+ oper
106
+ end
107
+ end
108
+
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+
5
+ include ForwardTo
6
+
7
+ class Parser
8
+ def initialize(file)
9
+ @file = file
10
+ end
11
+
12
+ def parse
13
+ yaml = YAML.load(IO.read(@file).sub(/^__END__$.*/m, ""), symbolize_names: true)
14
+ rules = nil
15
+ variables = {}
16
+ yaml.each { |key, value|
17
+ case key
18
+ when :rules; rules = value.map { |v| parse_rule(v) }
19
+ when /^\$[A-Z0-9_]+$/; variables[key.to_s] = parse_array(value)
20
+ else
21
+ raise "Illegal section: #{key}"
22
+ end
23
+ }
24
+ Spec.new(@file, rules, variables)
25
+ end
26
+
27
+ def self.parse(file) self.new(file).parse end
28
+
29
+ private
30
+ def parse_rule(hash)
31
+ tables = parse_array(hash[:tables]) or error "Can't find 'table' key"
32
+ rule = Rule.new(tables)
33
+ for oper in Spec::OPERS
34
+ value = hash[oper] or next
35
+ rule.send(:"#{oper}=", parse_oper(oper, value))
36
+ end
37
+ rule
38
+ end
39
+
40
+ def parse_oper(oper, value)
41
+ case value
42
+ when String; Oper.new(oper, [Access.new(parse_array(value), nil, nil, nil)])
43
+ when Hash; Oper.new(oper, [parse_access(value)])
44
+ when Array; Oper.new(oper, value.map { |hash| parse_access(hash) })
45
+ else
46
+ error "Illegal argument: #{value.invaluet}"
47
+ end
48
+ end
49
+
50
+ def parse_access(hash)
51
+ illegal_keys = hash.keys - Spec::FIELDS
52
+ illegal_keys.empty? or error "Illegal keys: #{illegal_keys.join(', ')}"
53
+ roles = parse_array(hash[:roles])
54
+ tables = parse_array(hash[:tables])
55
+ fields = parse_array(hash[:fields])
56
+ where = hash[:where]
57
+ Access.new(roles, tables, fields, where)
58
+ end
59
+
60
+ def parse_array(value)
61
+ case value
62
+ when String; value.split
63
+ when Array; value
64
+ when nil; nil
65
+ else
66
+ error "Illegal array value: #{value.inspect}"
67
+ end
68
+ end
69
+ end
70
+
@@ -0,0 +1,86 @@
1
+
2
+ class Spec
3
+ OPERS = [:select, :insert, :update, :delete, :attach]
4
+ FIELDS = [:roles, :tables, :fields, :where]
5
+
6
+ attr_reader :file
7
+ attr_accessor :rules
8
+ attr_accessor :variables
9
+
10
+ forward_to :variables, :[], :[]=
11
+
12
+ def initialize(file, rules, variables)
13
+ @file, @rules, @variables = file, rules, variables
14
+ end
15
+
16
+ def dump
17
+ puts "File: #{file}"
18
+ puts "Variables"
19
+ indent { variables.each { |k,v| puts "#{k} = #{v.inspect}" } }
20
+ puts "Rules"
21
+ indent { rules.sort_by { |rule| rule.tables.first }.each(&:dump) }
22
+ end
23
+ end
24
+
25
+ class Rule
26
+ attr_accessor :tables
27
+ attr_accessor *Spec::OPERS
28
+
29
+ def initialize(tables)
30
+ @tables = tables
31
+ Spec::OPERS.each { |op| self[op] = Oper.new(op) }
32
+ end
33
+
34
+ def opers() = Spec::OPERS.map { |op| self.send(op) }.compact
35
+ def [](key) = self.send(key)
36
+ def []=(key, value) self.send(:"#{key}=", value) end
37
+
38
+ def to_s() = "Rule, tables: #{tables.join(', ')}"
39
+
40
+ def dump
41
+ puts "Rule"
42
+ indent {
43
+ puts "tables: #{tables}"
44
+ opers.each { |op| op.dump }
45
+ }
46
+ end
47
+ end
48
+
49
+ class Oper
50
+ attr_reader :name
51
+ attr_accessor :accesses
52
+
53
+ def self.symbol = self.to_s.sub(/Decl/, "").downcase.to_sym
54
+
55
+ def initialize(name, accesses = [])
56
+ @name = name
57
+ @accesses = accesses
58
+ end
59
+
60
+ def dump
61
+ puts "#{name}"
62
+ indent { accesses.each(&:dump) }
63
+ end
64
+ end
65
+
66
+ class Access
67
+ attr_accessor *Spec::FIELDS
68
+
69
+ def initialize(roles, table, fields, where)
70
+ @roles = roles
71
+ @table = table
72
+ @fields = fields
73
+ @where = where
74
+ end
75
+
76
+ def dump
77
+ puts "access:"
78
+ indent {
79
+ Spec::FIELDS.each { |f|
80
+ value = self.send(f) or next
81
+ puts "#{f}: #{value}"
82
+ }
83
+ }
84
+ end
85
+ end
86
+
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MikrasUtils
4
- VERSION = "0.3.2"
4
+ VERSION = "0.4.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mikras_utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-07 00:00:00.000000000 Z
11
+ date: 2025-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg_conn
@@ -72,6 +72,7 @@ email:
72
72
  executables:
73
73
  - mikras_utils
74
74
  - mkacl
75
+ - rls
75
76
  extensions: []
76
77
  extra_rdoc_files: []
77
78
  files:
@@ -84,7 +85,9 @@ files:
84
85
  - build
85
86
  - exe/mikras_utils
86
87
  - exe/mkacl
88
+ - exe/rls
87
89
  - lib/mikras_utils.rb
90
+ - lib/mikras_utils/mikras.rb
88
91
  - lib/mikras_utils/mkacl.rb
89
92
  - lib/mikras_utils/mkacl/analyzer.rb
90
93
  - lib/mikras_utils/mkacl/generator.rb
@@ -93,8 +96,13 @@ files:
93
96
  - lib/mikras_utils/mkacl/generators/insert_triggers.rb
94
97
  - lib/mikras_utils/mkacl/generators/role_functions.rb
95
98
  - lib/mikras_utils/mkacl/generators/rules.rb
99
+ - lib/mikras_utils/mkacl/generators/seeds.rb
96
100
  - lib/mikras_utils/mkacl/parser.rb
101
+ - lib/mikras_utils/mkacl/simple_symtab.rb
97
102
  - lib/mikras_utils/mkacl/spec.rb
103
+ - lib/mikras_utils/rls/analyzer.rb
104
+ - lib/mikras_utils/rls/parser.rb
105
+ - lib/mikras_utils/rls/spec.rb
98
106
  - lib/mikras_utils/version.rb
99
107
  - sig/mikras_utils.rbs
100
108
  - tests/acl.fox