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

Constructor Details

#initializeModelObject

Returns a new instance of ModelObject.



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

def initialize
  @changed = false
  @log_events = []
end

Class Method Details

.changes_are_loggedObject



53
54
55
56
# File 'lib/model.rb', line 53

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

.create_interactively(opts = {}) ⇒ Object



103
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
# File 'lib/model.rb', line 103

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:



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/model.rb', line 24

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



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

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

.from(fn) ⇒ Object



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

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



16
17
18
19
20
# File 'lib/model.rb', line 16

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



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

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

.yaml_other_thingObject



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

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

Instance Method Details

#after_deserialize(*a) ⇒ Object



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

def after_deserialize(*a); end

#before_serialize(*a) ⇒ Object



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

def before_serialize(*a); end

#changed!Object



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

def changed!; @changed = true end

#changed?Boolean

Returns:

  • (Boolean)


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

def changed?; @changed end

#each_modelobjectObject

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



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/model.rb', line 65

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



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

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

#save!(fn) ⇒ Object



84
85
86
87
88
# File 'lib/model.rb', line 84

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

#to_yaml_propertiesObject



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

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

#to_yaml_typeObject



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

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