Class: AgentCode::Blueprint::Generators::PolicyGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/agentcode/blueprint/generators/policy_generator.rb

Overview

Generates fully working Ruby policy classes with role-based attribute permissions. Port of agentcode-adonis-server policy_generator.ts.

Instance Method Summary collapse

Instance Method Details

#build_hidden_attributes_method(permissions) ⇒ String

Build the hidden_attributes_for_show method.

Parameters:

  • permissions (Hash<String, Hash>)

Returns:

  • (String)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/agentcode/blueprint/generators/policy_generator.rb', line 120

def build_hidden_attributes_method(permissions)
  # Filter to only roles with hidden_fields
  hidden_perms = permissions.select { |_, perm| perm[:hidden_fields]&.any? }

  if hidden_perms.empty?
    return <<~RUBY.chomp
        def hidden_attributes_for_show(user)
          []
        end
    RUBY
  end

  groups = group_roles_by_fields(
    hidden_perms.transform_values { |p| { show_fields: p[:hidden_fields] } },
    :show_fields
  )

  lines = []
  lines << "  def hidden_attributes_for_show(user)"

  groups.each do |group|
    condition = build_role_condition(group[:roles])
    array_str = fields_to_ruby_array(group[:fields])
    lines << "    return #{array_str} if #{condition}"
  end

  lines << "    []"
  lines << "  end"

  lines.join("\n")
end

#build_permitted_attributes_method(method_name, permissions, field_key) ⇒ String

Build a permitted_attributes method body.

Parameters:

  • method_name (String)
  • permissions (Hash<String, Hash>)
  • field_key (Symbol)

Returns:

  • (String)


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/agentcode/blueprint/generators/policy_generator.rb', line 90

def build_permitted_attributes_method(method_name, permissions, field_key)
  groups = group_roles_by_fields(permissions, field_key)

  if groups.empty?
    return <<~RUBY.chomp
        def #{method_name}(user)
          ['*']
        end
    RUBY
  end

  lines = []
  lines << "  def #{method_name}(user)"

  groups.each do |group|
    condition = build_role_condition(group[:roles])
    array_str = fields_to_ruby_array(group[:fields])
    lines << "    return #{array_str} if #{condition}"
  end

  lines << "    []"
  lines << "  end"

  lines.join("\n")
end

#build_role_condition(roles) ⇒ String

Build a role condition string.

Parameters:

  • roles (Array<String>)

Returns:

  • (String)

    e.g. "has_role?(user, 'admin') || has_role?(user, 'editor')"



61
62
63
# File 'lib/agentcode/blueprint/generators/policy_generator.rb', line 61

def build_role_condition(roles)
  roles.map { |r| "has_role?(user, '#{r}')" }.join(" || ")
end

#fields_to_ruby_array(fields) ⇒ String

Convert field array to Ruby array literal.

Parameters:

  • fields (Array<String>)

Returns:

  • (String)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/agentcode/blueprint/generators/policy_generator.rb', line 69

def fields_to_ruby_array(fields)
  return "[]" if fields.empty?
  return "['*']" if fields == ["*"]

  items = fields.map { |f| "'#{f}'" }
  inline = "[#{items.join(', ')}]"

  if inline.length <= 80
    inline
  else
    lines = items.join(",\n        ")
    "[\n        #{lines},\n      ]"
  end
end

#generate(blueprint) ⇒ String

Generate a complete policy class.

Parameters:

  • blueprint (Hash)

    ParsedBlueprint

Returns:

  • (String)

    Ruby source code



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/agentcode/blueprint/generators/policy_generator.rb', line 13

def generate(blueprint)
  model_name = blueprint[:model]
  slug = blueprint[:slug]
  permissions = blueprint[:permissions]

  show_method = build_permitted_attributes_method("permitted_attributes_for_show", permissions, :show_fields)
  hidden_method = build_hidden_attributes_method(permissions)
  create_method = build_permitted_attributes_method("permitted_attributes_for_create", permissions, :create_fields)
  update_method = build_permitted_attributes_method("permitted_attributes_for_update", permissions, :update_fields)

  <<~RUBY
    # frozen_string_literal: true

    class #{model_name}Policy < AgentCode::ResourcePolicy
      self.resource_slug = '#{slug}'

    #{show_method}
    #{hidden_method}
    #{create_method}
    #{update_method}
    end
  RUBY
end

#group_roles_by_fields(permissions, field_key) ⇒ Array<Hash>

Group roles with identical field sets into combined conditions.

Parameters:

  • permissions (Hash<String, Hash>)
  • field_key (Symbol)

    :show_fields, :create_fields, etc.

Returns:

  • (Array<Hash>)

    [{ fields: [...], roles: [...] }, ...]



42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/agentcode/blueprint/generators/policy_generator.rb', line 42

def group_roles_by_fields(permissions, field_key)
  groups = {}

  permissions.each do |role, perm|
    fields = perm[field_key] || []
    next if fields.empty?

    key = fields.sort.join(",")
    groups[key] ||= { fields: fields, roles: [] }
    groups[key][:roles] << role
  end

  groups.values
end