Class: Ditz::ModelObject

Inherits:
Object show all
Defined in:
lib/model.rb

Direct Known Subclasses

Component, Config, Issue, Project, Release

Defined Under Namespace

Classes: ModelError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.changes_are_loggedObject



60
61
62
63
# File 'lib/model.rb', line 60

def self.changes_are_logged
  define_method(:changes_are_logged?) { true }
  field :log_events, :multi => true, :ask => false
end

.create_interactively(opts = {}) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/model.rb', line 104

def self.create_interactively opts={}
  o = self.new
  args = opts[:args] || []
  @fields.each do |name, field_opts|
    val = if opts[:with] && opts[:with][name]
      opts[:with][name]
    elsif field_opts[:generator].is_a? Proc
      field_opts[:generator].call(*args)
    elsif field_opts[:generator]
      o.send field_opts[:generator], *args
    elsif field_opts[:ask] == false # nil counts as true here
      field_opts[:default] || (field_opts[:multi] ? [] : nil)
    else
      q = field_opts[:prompt] || name.to_s.ucfirst
      if field_opts[:multiline]
        ask_multiline q
      else
        default = if field_opts[:default_generator].is_a? Proc
          field_opts[:default_generator].call(*args)
        elsif field_opts[:default_generator]
          o.send field_opts[:default_generator], *args
        elsif field_opts[:default]
          field_opts[:default]
        end
          
        ask q, :default => default
      end
    end
    o.send("#{name}=", val)
  end
  o
end

.field(name, opts = {}) ⇒ Object

Raises:



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/model.rb', line 31

def self.field name, opts={}
  @fields ||= [] # can't use a hash because want to preserve field order when serialized
  raise ModelError, "field with name #{name} already defined" if @fields.any? { |k, v| k == name }
  @fields << [name, opts]

  attr_reader name
  if opts[:multi]
    single_name = name.to_s.sub(/s$/, "") # oh yeah
    define_method "add_#{single_name}" do |obj|
      array = self.instance_variable_get("@#{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!
      array << obj
    end

    define_method "drop_#{single_name}" do |obj|
      return unless self.instance_variable_get("@#{name}").delete obj
      changed!
      obj
    end
  end
  define_method "#{name}=" do |o|
    changed!
    instance_variable_set "@#{name}", o
  end
end

.fieldsObject



58
# File 'lib/model.rb', line 58

def self.fields; @fields.map { |name, opts| name } end

.from(fn) ⇒ Object



65
66
67
68
69
# File 'lib/model.rb', line 65

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
  end
end

.inherited(subclass) ⇒ Object



23
24
25
26
27
# File 'lib/model.rb', line 23

def self.inherited subclass
  YAML.add_domain_type(yaml_domain, subclass.yaml_other_thing) do |type, val|
    YAML.object_maker(subclass, val)
  end
end

.yaml_domainObject

yamlability



19
# File 'lib/model.rb', line 19

def self.yaml_domain; "ditz.rubyforge.org,2008-03-06" end

.yaml_other_thingObject



20
# File 'lib/model.rb', line 20

def self.yaml_other_thing; name.split('::').last.dcfirst end

Instance Method Details

#after_deserialize(*a) ⇒ Object



29
# File 'lib/model.rb', line 29

def after_deserialize(*a); end

#before_serialize(*a) ⇒ Object



28
# File 'lib/model.rb', line 28

def before_serialize(*a); end

#changed!Object



102
# File 'lib/model.rb', line 102

def changed!; @changed = true end

#changed?Boolean

Returns:

  • (Boolean)


101
# File 'lib/model.rb', line 101

def changed?; @changed ||= false end

#each_modelobjectObject

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



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/model.rb', line 72

def each_modelobject
  seen = {}
  to_see = [self]
  until to_see.empty?
    cur = to_see.pop
    seen[cur] = true
    yield cur
    cur.class.fields.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

#log(what, who, comment) ⇒ Object



96
97
98
99
# File 'lib/model.rb', line 96

def log what, who, comment
  add_log_event([Time.now, who, what, comment])
  self
end

#save!(fn) ⇒ Object



91
92
93
94
# File 'lib/model.rb', line 91

def save! fn
  #FileUtils.mv fn, "#{fn}~", :force => true rescue nil
  File.open(fn, "w") { |f| f.puts to_yaml }
end

#to_yaml_propertiesObject



22
# File 'lib/model.rb', line 22

def to_yaml_properties; self.class.fields.map { |f| "@#{f.to_s}" } end

#to_yaml_typeObject



21
# File 'lib/model.rb', line 21

def to_yaml_type; "!#{self.class.yaml_domain}/#{self.class.yaml_other_thing}" end