In Files

Parent

Ditz::ModelObject

Attributes

fields[R]
serialized_values[R]
values[R]

Public Class Methods

changes_are_logged() click to toggle source
# File lib/model.rb, line 108
def self.changes_are_logged
  define_method(:changes_are_logged?) { true }
  field :log_events, :multi => true, :ask => false
end
create(generator_args, vals={}) click to toggle source

creates the object, filling in fields from ‘vals’, and throwing a ModelError when it can’t find all the requisite fields

# File lib/model.rb, line 222
def create generator_args, vals={}
  o = self.new
  @fields.each do |name, opts|
    val = if vals[name]
      vals[name]
    elsif(found, x = generate_field_value(o, opts, generator_args)) && found
      x
    else
      raise ModelError, "missing required field #{name}"
    end
    o.send "#{name}=", val
  end
  o
end
create_interactively(opts={}) click to toggle source

creates the object, prompting the user when necessary. can take a :with => { hash } parameter for pre-filling model fields.

can also take a :defaults_from => obj parameter for pre-filling model fields from another object with (some of) those fields. kinda like a bizarre interactive copy constructor.

# File lib/model.rb, line 192
def create_interactively opts={}
  o = self.new
  generator_args = opts[:args] || []
  @fields.each do |name, field_opts|
    val = if opts[:with] && opts[:with][name]
      opts[:with][name]
    elsif(found, x = generate_field_value(o, field_opts, generator_args)) && found
      x
    else
      q = field_opts[:prompt] || name.to_s.capitalize
      if field_opts[:multiline]
        ## multiline options currently aren't allowed to have a default
        ## value, so just ask.
        ask_multiline q
      else
        default = if opts[:defaults_from] && opts[:defaults_from].respond_to?(name) && (x = opts[:defaults_from].send(name))
          x
        else
          default = generate_field_default o, field_opts, generator_args
        end
        ask q, :default => default
      end
    end
    o.send "#{name}=", val
  end
  o
end
field(name, opts={}) click to toggle source

add a new field to a model object

# File lib/model.rb, line 58
def self.field name, opts={}
  @fields ||= [] # can't use a hash because we need to preserve field order
  raise ModelError, "field with name #{name} already defined" if @fields.any? { |k, v| k == name }
  @fields << [name, opts]

  if opts[:multi]
    single_name = name.to_s.sub(/s$/, "") # oh yeah
    define_method "add_#{single_name}" do |obj|
      array = send(name)
      raise ModelError, "already has a #{single_name} with name #{obj.name.inspect}" if obj.respond_to?(:name) && array.any? { |o| o.name == obj.name }
      changed!
      @serialized_values.delete name
      array << obj
    end

    define_method "drop_#{single_name}" do |obj|
      return unless @values[name].delete obj
      @serialized_values.delete name
      changed!
      obj
    end
  end

  define_method "#{name}=" do |o|
    changed!
    @serialized_values.delete name
    @values[name] = o
  end

  define_method "__serialized_#{name}=" do |o|
    changed!
    @values.delete name
    @serialized_values[name] = o
  end

  define_method "__serialized_#{name}" do
    @serialized_values[name]
  end

  define_method name do
    return @values[name] if @values.member?(name)
    @values[name] = deserialized_form_of name, @serialized_values[name]
  end
end
field_names() click to toggle source
# File lib/model.rb, line 103
def self.field_names; @fields.map { |name, opts| name } end
from(fn) click to toggle source
# File lib/model.rb, line 113
def self.from fn
  returning YAML::load_file(fn) do |o|
    raise ModelError, "error loading from yaml file #{fn.inspect}: expected a #{self}, got a #{o.class}" unless o.class == self
    o.pathname = fn if o.respond_to? :pathname=

    o.class.fields.each do |f, opts|
      m = "__serialized_#{f}"
      if opts[:multi] && o.send(m).nil?
        $stderr.puts "Warning: corrected nil multi-field #{f}"
        o.send "#{m}=", []
      end
    end
  end
end
inherited(subclass) click to toggle source
# File lib/model.rb, line 28
def self.inherited subclass
  YAML.add_domain_type(yaml_domain, subclass.yaml_other_thing) do |type, val|
    o = subclass.new
    val.each do |k, v|
      m = "__serialized_#{k}="
      if o.respond_to? m
        o.send m, v
      else
        $stderr.puts "warning: unknown field #{k.inspect} in YAML for #{type}; ignoring"
      end
    end
    o.unchanged!
    o
  end
end
new() click to toggle source
# File lib/model.rb, line 18
def initialize
  @values = {}
  @serialized_values = {}
  self.class.fields.map { |f, opts| @values[f] = [] if opts[:multi] }
end
yaml_domain() click to toggle source

yamlability

# File lib/model.rb, line 25
def self.yaml_domain; "ditz.rubyforge.org,2008-03-06" end
yaml_other_thing() click to toggle source
# File lib/model.rb, line 26
def self.yaml_other_thing; name.split('::').last.dcfirst end

Public Instance Methods

changed!() click to toggle source
# File lib/model.rb, line 182
def changed!; @changed = true end
changed?() click to toggle source
# File lib/model.rb, line 181
def changed?; @changed ||= false end
deserialized_form_of(field, value) click to toggle source

override these two to model per-field transformations between disk and memory.

convert disk form => memory form

# File lib/model.rb, line 48
def deserialized_form_of field, value
  @serialized_values[field]
end
each_modelobject() click to toggle source

depth-first search on all reachable ModelObjects. fuck yeah.

# File lib/model.rb, line 135
def each_modelobject
  seen = {}
  to_see = [self]
  until to_see.empty?
    cur = to_see.pop
    seen[cur] = true
    yield cur
    cur.class.field_names.each do |f|
      val = cur.send(f)
      next if seen[val]
      if val.is_a?(ModelObject)
        to_see.push val
      elsif val.is_a?(Array)
        to_see += val.select { |v| v.is_a?(ModelObject) }
      end
    end
  end
end
inspect() click to toggle source
# File lib/model.rb, line 132
def inspect; to_s end
log(what, who, comment) click to toggle source
# File lib/model.rb, line 176
def log what, who, comment
  add_log_event([Time.now, who, what, comment || ""])
  self
end
save!(fn) click to toggle source
# File lib/model.rb, line 154
def save! fn
  #FileUtils.mv fn, "#{fn}~", :force => true rescue nil
  File.open(fn, "w") { |f| f.puts to_yaml }
  self
end
serialized_form_of(field, value) click to toggle source

convert memory form => disk form

# File lib/model.rb, line 53
def serialized_form_of field, value
  @values[field]
end
to_s() click to toggle source
# File lib/model.rb, line 128
def to_s
  "<#{self.class.name}: " + self.class.field_names.map { |f| "#{f}: " + (@values[f].to_s || @serialized_values[f]).inspect }.join(", ") + ">"
end
to_yaml(opts={}) click to toggle source
# File lib/model.rb, line 160
def to_yaml opts={}
  YAML::quick_emit(object_id, opts) do |out|
    out.map(taguri, nil) do |map|
      self.class.fields.each do |f, fops|
        v = if @serialized_values.member?(f)
          @serialized_values[f]
        else
          @serialized_values[f] = serialized_form_of f, @values[f]
        end

        map.add f.to_s, v
      end
    end
  end
end
to_yaml_type() click to toggle source
# File lib/model.rb, line 27
def to_yaml_type; "!#{self.class.yaml_domain}/#{self.class.yaml_other_thing}" end
unchanged!() click to toggle source
# File lib/model.rb, line 183
def unchanged!; @changed = false end

[Validate]

Generated with the Darkfish Rdoc Generator 2.