Class: Command::Subject

Inherits:
Object
  • Object
show all
Defined in:
lib/command-set/subject.rb

Overview

This object represents the subject of a command set. To expose parts of the application to the command set, commands should call subject_methods with the names of methods it expects to use.

Furthermore, Subject maintains the state of the command set, which helps put all of the logic in the Command objects by letting them maintain state in one place

Subjects are very picky about their fields. The motivation here is to fail fast. Commands can’t access fields they don’t declare with DSL::CommandDefinition#subject_methods, and the interpreter will fail fast unless the required fields have been assigned.

Finally, Commands can’t set fields - but the fields are the same for each command, so they can change the fields. For drastic changes, try Array#replace or Hash#replace

Direct Known Subclasses

PermissiveSubject

Defined Under Namespace

Classes: UndefinedField

Constant Summary collapse

Undefined =
UndefinedField.new

Instance Method Summary collapse

Constructor Details

#initializeSubject

Returns a new instance of Subject.



22
23
24
25
26
# File 'lib/command-set/subject.rb', line 22

def initialize
  @fields = {}
  @contexts = {}
  @protected_subfields = Hash.new {|h,k| h[k] = []}
end

Instance Method Details

#absorb(other) ⇒ Object



116
117
118
119
120
121
122
123
# File 'lib/command-set/subject.rb', line 116

def absorb(other)
  other.all_fields.each do |name|
    add_field_writer(name)
  end

  copy_fields(other)
  copy_contexts(other)
end

#get_image(with_fields, in_context = []) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/command-set/subject.rb', line 62

def get_image(with_fields, in_context=[])
  in_context = in_context.dup
  fields = @fields.dup
  context = self
  until in_context.empty?
    protected_fields = @protected_subfields[in_context]
    context_name = in_context.shift.to_sym
    context = context.contexts[context_name]
    raise CommandError, "no context: #{context_name}" if context.nil?
    context.fields.each_pair do |name, value|
      if not fields.key?(name) or fields[name] == Undefined or 
        protected_fields.include?(name)
        fields[name] = value
      end
    end
  end

  image = SubjectImage.new
  with_fields.map! {|field| field.to_s}
  missing_fields = with_fields - fields.keys
  unless missing_fields.empty? 
    raise CommandError, "Subject is missing fields: #{missing_fields.join(", ")}"
  end
  with_fields.each do |field|
    image.add_field(field, fields[field])
  end
  return image
end

#merge(context, other) ⇒ Object

Raises:



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/command-set/subject.rb', line 97

def merge(context, other)
  other.fields.keys.each do |name|
    add_field_writer(name)
  end

  unless context.nil?
    context = context.to_sym
    if @contexts[context].nil?
      return create_context(context, other)
    else
      return @contexts[context].merge(nil, other)
    end
  end

  raise CommandError unless (defined_fields & other.defined_fields).empty?

  copy_fields(other)
end

#protect(*path) ⇒ Object



91
92
93
94
95
# File 'lib/command-set/subject.rb', line 91

def protect(*path)
  field_name = path.pop.to_s
  path.map! {|el| el.to_sym}
  @protected_subfields[path] << field_name
end

#required_fields(field_names, required_at = []) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/command-set/subject.rb', line 28

def required_fields(field_names, required_at=[])
  unless required_at.empty?
    unless @contexts.has_key?(required_at.first)
      create_context(required_at.first, Subject.new)
    end
    return @contexts[required_at.shift].required_fields(field_names, 
                                                        required_at)
  end

  field_names.map! {|name| name.to_s}
  field_names -= instance_variables.map {|var| var.sub(/^@/, "")}
  bad_fields = field_names.find_all do |name|
    @contexts.has_key?(name.to_sym)
  end
  unless bad_fields.empty?
    raise CommandError, "#{bad_fields.join(", ")} are context names!" 
  end
  
  field_names.each do |field|
    add_field(field)
  end
end

#verifyObject



51
52
53
54
55
56
57
58
59
60
# File 'lib/command-set/subject.rb', line 51

def verify
  missing = @fields.keys.find_all do |var| 
    UndefinedField === @fields[var]
  end
  unless missing.empty?
    missing.map! {|m| m.sub(/^@/,"")}
    raise RuntimeError, "Undefined subject field#{missing.length > 1 ? "s" : ""}: #{missing.join(", ")}" 
  end	
  return nil
end