Class: Eaco::Designator

Inherits:
String
  • Object
show all
Defined in:
lib/eaco/designator.rb

Overview

A Designator characterizes an Actor.

Example: an User Actor is uniquely identified by its numerical id, as such we can define an user designator that designs User 42 as user:42.

The same User also could belong to the group frobber, uniquely identified by its name. We can then define a group designator that would design the same User as group:frobber.

In ACLs designators are given roles, and the intersection between the designators of an Actor and the ones defined in the ACL gives the role of the Actor for the Resource that the ACL secures.

Designators for actors are defined through the DSL, see Eaco::DSL::Actor

See Also:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, instance = nil) ⇒ Designator

Initializes the designator with the given value. The string representation is then calculated by concatenating the type and the given value.

An optional instance can be attached, if you use to pass around designators in your app.

Parameters:

  • value (String)

    the unique ID valid in this designator namespace

  • instance (Actor) (defaults to: nil)

    optional Actor instance


195
196
197
198
# File 'lib/eaco/designator.rb', line 195

def initialize(value, instance = nil)
  @value, @instance = value, instance
  super([ self.class.id, value ].join(':'))
end

Instance Attribute Details

#instanceObject

The instance given to #initialize


204
205
206
# File 'lib/eaco/designator.rb', line 204

def instance
  @instance
end

#valueObject (readonly)

This designator unique ID in the namespace of the designator type.


201
202
203
# File 'lib/eaco/designator.rb', line 201

def value
  @value
end

Class Method Details

.configure!(options) ⇒ Object

Sets up the designator implementation with the given options. Currently:

  • :from - defines the method to call on the Actor to obtain the unique

    IDs for this Designator class.
    

Example configuration:

actor User do
  designators do
    user  from: :id
    group from: :group_ids
  end
end

This method is called from the DSL.


90
91
92
93
94
95
96
# File 'lib/eaco/designator.rb', line 90

def configure!(options)
  @method = options.fetch(:from)
  self

rescue KeyError
  raise Malformed, "The designator option :from is required"
end

.designator_nameObject

Returns this class' demodulized name


137
138
139
# File 'lib/eaco/designator.rb', line 137

def designator_name
  self.name.split('::').last
end

.harvest(actor) ⇒ Array

Harvests valid designators for the given Actor.

It calls the @method defined through the :from option passed when configuring the designators (see configure!).

Parameters:

Returns:

  • (Array)

    an array of Designator objects the Actor owns.

See Also:


110
111
112
113
114
# File 'lib/eaco/designator.rb', line 110

def harvest(actor)
  list = actor.send(@method)
  list = list.to_a if list.respond_to?(:to_a)
  Array.new([list]).flatten.map! {|value| new(value) }
end

.idSymbol Also known as: type

Returns the designator type.

The type symbol is derived from the class name, on the other way around, the Eaco::DSL looks up designator implementation classes from the designator type symbol.

Example:

>> User::Designators::Group.id
=> :group

157
158
159
160
161
# File 'lib/eaco/designator.rb', line 157

def id
  @_id ||= self.designator_name.gsub(/([a-z])?([A-Z])/) do |x|
    [$1, $2.downcase].compact.join '_'
  end.intern
end

.label(value = nil) ⇒ String

Sets this Designator label to the given value.

Example:

class User::Designators::Group < Eaco::Designator
  label "Active Directory Group"
end

Parameters:

  • value (String) (defaults to: nil)

    the designator label

Returns:

  • (String)

    the configured label


129
130
131
132
# File 'lib/eaco/designator.rb', line 129

def label(value = nil)
  @label = value if value
  @label ||= designator_name
end

.make(type, value) ⇒ Designator

Instantiate a designator of the given type with the given value.

Example:

>> Designator.make('user', 42)
=> #<Designator(User) value:42>

Parameters:

  • type (String)

    the designator type (e.g. user)

  • value (String)

    the designator value. It will be stringified using .to_s.

Returns:


38
39
40
# File 'lib/eaco/designator.rb', line 38

def make(type, value)
  Eaco::DSL::Actor.find_designator(type).new(value)
end

.parse(string) ⇒ Designator

Parses a Designator string representation and instantiates a new Designator instance from it.

>> Designator.parse('user:42')
=> #<Designator(User) value:42>

Parameters:

  • string (String)

    the designator string representation.

Returns:


53
54
55
56
# File 'lib/eaco/designator.rb', line 53

def parse(string)
  return string if string.is_a?(Designator)
  make(*string.split(':', 2))
end

.resolve(designators) ⇒ Array

Resolves one or more designators into the target actors.

Parameters:

  • designators (Array)

    designator string representations.

Returns:

  • (Array)

    resolved actors, application-dependant.


65
66
67
# File 'lib/eaco/designator.rb', line 65

def resolve(designators)
  Array.new(designators||[]).inject(Set.new) {|ret, d| ret.merge parse(d).resolve}
end

.search(query) ⇒ Enumerable

Searches designator definitions using the given query.

To be implemented by derived classes. E.g. for a “User” designator this would return your own User instances that you may want to display in a typeahead menu, for your Enterprise authorization management UI… :-)

Parameters:

  • query (String)

    the query to search against

Returns:

  • (Enumerable)

    application Actors collection

Raises:

  • (NotImplementedError)

177
178
179
180
181
# File 'lib/eaco/designator.rb', line 177

def search(query)
  # :nocov:
  raise NotImplementedError
  # :nocov:
end

Instance Method Details

#as_json(options = nil) ⇒ Hash

Converts this designator to an Hash for .to_json to work.

Parameters:

  • options (Ignored) (defaults to: nil)

Returns:

  • (Hash)

241
242
243
# File 'lib/eaco/designator.rb', line 241

def as_json(options = nil)
  { :value => to_s, :label => describe(:full) }
end

#describe(style = nil) ⇒ String

Should return an extended description for this designator. You can then use this to display it in your application.

E.g. for an “User” designator this would be the user name, for a “Group” designator this would be the group name.

Parameters:

  • style (Symbol) (defaults to: nil)

    the description style. #as_json uses :full, but you are free to define whatever styles you do see fit.

Returns:

  • (String)

    the description


218
219
220
# File 'lib/eaco/designator.rb', line 218

def describe(style = nil)
  nil
end

#inspectString

Pretty prints the designator in your console.

Returns:

  • (String)

250
251
252
# File 'lib/eaco/designator.rb', line 250

def inspect
  %[#<Designator(#{self.class.designator_name}) value:#{value.inspect}>]
end

#labelString

Returns the designator's class label.

Returns:

  • (String)

    the designator's class label.

See Also:


259
260
261
# File 'lib/eaco/designator.rb', line 259

def label
  self.class.label
end

#resolveObject

Translates this designator to concrete Actor instances in your application. To be implemented by derived classes.

Raises:

  • (NotImplementedError)

228
229
230
231
232
# File 'lib/eaco/designator.rb', line 228

def resolve
  # :nocov:
  raise NotImplementedError
  # :nocov:
end

#typeSymbol

Returns the designator's class type.

Returns:

  • (Symbol)

    the designator's class type.

See Also:


268
269
270
# File 'lib/eaco/designator.rb', line 268

def type
  self.class.type
end