Class: CommandModel::Model

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming
Includes:
ActiveModel::Conversion, ActiveModel::Validations
Defined in:
lib/command_model/model.rb

Defined Under Namespace

Classes: Parameter

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parameters = {}) ⇒ Model

Accepts a parameters hash or another of the same class. If another instance of the same class is passed in then the parameters are copied to the new object.



140
141
142
143
# File 'lib/command_model/model.rb', line 140

def initialize(parameters={})
  @type_conversion_errors = {}
  set_parameters parameters
end

Class Method Details

.attr_type_converting_writer(name, converters) ⇒ Object

:nodoc



60
61
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
90
91
# File 'lib/command_model/model.rb', line 60

def self.attr_type_converting_writer(name, converters) #:nodoc
  converters = converters.map do |c|
    if c.respond_to? :call
      c
    else
      case c.to_s
      when "integer"
        CommandModel::Convert::Integer.new
      when "decimal"
        CommandModel::Convert::Decimal.new
      when "float"
        CommandModel::Convert::Float.new
      when "date"
        CommandModel::Convert::Date.new
      when "boolean"
        CommandModel::Convert::Boolean.new
      else
        raise ArgumentError, "unknown converter #{c}"
      end
    end
  end

  define_method "#{name}=" do |value|
    converted_value = converters.reduce(value) { |v, c| c.call(v) }
    instance_variable_set "@#{name}", converted_value
    instance_variable_get("@type_conversion_errors").delete(name)
    instance_variable_get "@#{name}"
  rescue CommandModel::Convert::ConvertError => e
    instance_variable_get("@type_conversion_errors")[name] = e.target_type
    instance_variable_set "@#{name}", value
  end
end

.execute(attributes_or_command, &block) ⇒ Object

Executes a block of code if the command model is valid.

Accepts either a command model or a hash of attributes with which to create a new command model.

Examples

RenameUserCommand.execute(:login => "john") do |command|
  if allowed_to_rename_user?
    self. = command.
  else
    command.errors.add :base, "not allowed to rename"
  end
end


107
108
109
110
111
112
113
114
115
# File 'lib/command_model/model.rb', line 107

def self.execute(attributes_or_command, &block)
  command = if attributes_or_command.kind_of? self
    attributes_or_command
  else
    new(attributes_or_command)
  end

  command.call &block
end

.failure(error) ⇒ Object

Quickly create a failed command object. Requires one parameter with the description of what went wrong. This is used when the command takes no parameters to want to take advantage of the success? and errors properties of a command object.



130
131
132
133
134
135
# File 'lib/command_model/model.rb', line 130

def self.failure(error)
  new.tap do |instance|
    instance.execution_attempted!
    instance.errors.add(:base, error)
  end
end

.parameter(*args) ⇒ Object

Parameter requires one or more attributes as its first parameter(s). It accepts an options hash as its last parameter.

Options

  • convert - An object or array of objects that respond to call and convert the assigned value as necessary. Built-in converters exist for integer, decimal, float, date, and boolean. These built-in converters can be specified by symbol.

  • validations - All other options are considered validations and are passed to ActiveModel::Validates.validates

Examples

parameter :gender
parameter :name, presence: true
parameter :birthdate, convert: :date
parameter :height, :weight,
  convert: [CommandModel::Convert::StringMutator.new { |s| s.gsub(",", "")}, :integer],
  presence: true,
  numericality: { :greater_than_or_equal_to => 0 }


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/command_model/model.rb', line 38

def self.parameter(*args)
  options = args.last.kind_of?(Hash) ? args.pop.clone : {}
  converters = options.delete(:convert)

  args.each do |name|
    attr_reader name

    if converters
      attr_type_converting_writer name, Array(converters)
    else
      attr_writer name
    end
    validates name, options.clone if options.present? # clone options because validates mutates the hash :(
    parameters.push Parameter.new name, converters, options
  end
end

.parametersObject

Returns array of all parameters defined for class



56
57
58
# File 'lib/command_model/model.rb', line 56

def self.parameters
  @parameters ||= []
end

.successObject

Quickly create a successful command object. This is used when the command takes no parameters to want to take advantage of the success? and errors properties of a command object.



120
121
122
123
124
# File 'lib/command_model/model.rb', line 120

def self.success
  new.tap do |instance|
    instance.execution_attempted!
  end
end

Instance Method Details

#call(&block) ⇒ Object

Executes the command by calling the method execute if the validations pass.



147
148
149
150
151
# File 'lib/command_model/model.rb', line 147

def call(&block)
  execute(&block) if valid?
  execution_attempted!
  self
end

#execute {|_self| ... } ⇒ Object

Performs the actual command execution. It does not test if the command parameters are valid. Typically, call should be called instead of calling execute directly.

execute should be overridden in descendent classes

Yields:

  • (_self)

Yield Parameters:



158
159
160
# File 'lib/command_model/model.rb', line 158

def execute
  yield self if block_given?
end

#execution_attempted!Object

Record that an attempt was made to execute this command whether or not it was successful.



164
165
166
# File 'lib/command_model/model.rb', line 164

def execution_attempted! #:nodoc:
  @execution_attempted = true
end

#execution_attempted?Boolean

True if execution has been attempted on this command

Returns:

  • (Boolean)


169
170
171
# File 'lib/command_model/model.rb', line 169

def execution_attempted?
  @execution_attempted
end

#parametersObject

Returns hash of all parameter names and values



179
180
181
182
183
# File 'lib/command_model/model.rb', line 179

def parameters
  self.class.parameters.each_with_object({}) do |parameter, hash|
    hash[parameter.name] = send(parameter.name)
  end
end

#persisted?Boolean

:nodoc:

Returns:

  • (Boolean)


194
195
196
# File 'lib/command_model/model.rb', line 194

def persisted?
  false
end

#set_parameters(hash_or_instance) ⇒ Object

Sets parameter(s) from hash or instance of same class



186
187
188
189
190
191
# File 'lib/command_model/model.rb', line 186

def set_parameters(hash_or_instance)
  parameters = extract_parameters_from_hash_or_instance(hash_or_instance)
  parameters.each do |k,v|
    send "#{k}=", v
  end
end

#success?Boolean

Command has been executed without errors

Returns:

  • (Boolean)


174
175
176
# File 'lib/command_model/model.rb', line 174

def success?
  execution_attempted? && errors.empty?
end