mikras_utils 0.3.2 → 0.4.0

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.
@@ -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