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.



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

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

Class Method Details

.attr_type_converting_writer(name, converters) ⇒ Object

:nodoc



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/command_model/model.rb', line 52

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


99
100
101
102
103
104
105
106
107
# File 'lib/command_model/model.rb', line 99

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.



122
123
124
125
126
127
# File 'lib/command_model/model.rb', line 122

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 }


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/command_model/model.rb', line 30

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



48
49
50
# File 'lib/command_model/model.rb', line 48

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.



112
113
114
115
116
# File 'lib/command_model/model.rb', line 112

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.



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

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:



150
151
152
# File 'lib/command_model/model.rb', line 150

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.



156
157
158
# File 'lib/command_model/model.rb', line 156

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

#execution_attempted?Boolean

True if execution has been attempted on this command

Returns:

  • (Boolean)


161
162
163
# File 'lib/command_model/model.rb', line 161

def execution_attempted?
  @execution_attempted
end

#parametersObject

Returns hash of all parameter names and values



171
172
173
174
175
# File 'lib/command_model/model.rb', line 171

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

#persisted?Boolean

:nodoc:

Returns:

  • (Boolean)


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

def persisted?
  false
end

#set_parameters(hash_or_instance) ⇒ Object

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



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

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)


166
167
168
# File 'lib/command_model/model.rb', line 166

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