Class: Og::Manager

Inherits:
Object show all
Defined in:
lib/og/manager.rb,
lib/og/evolution.rb

Overview

A Manager defines the relations between entities, ie objects managed by Og.

Defined Under Namespace

Classes: EntityInfo

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Manager

Returns a new instance of Manager.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/og/manager.rb', line 41

def initialize(options)
  @options = options
  @entities = {}
  @pool = Pool.new

  @store_class = Store.for_name(options[:store])
  @store_class.destroy(options) if options[:destroy]
  @store_class.destroy_tables(options) if options[:destroy_tables]

  if Og.thread_safe
    (options[:connection_count] || 5).times do
      @pool << @store_class.new(options)
    end
  else
    @store = @store_class.new(options)
  end
end

Instance Attribute Details

#entitiesObject

The collection of Entities managed by this manager.



39
40
41
# File 'lib/og/manager.rb', line 39

def entities
  @entities
end

#optionsObject

The configuration options.



30
31
32
# File 'lib/og/manager.rb', line 30

def options
  @options
end

#store=(value) ⇒ Object

The store used for persistence. This is a virtual field when running in thread_safe mode.



35
36
37
# File 'lib/og/manager.rb', line 35

def store=(value)
  @store = value
end

Instance Method Details

#dump(options = {}) ⇒ Object Also known as: export

Dump Og managed objects to the filesystem.



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/og/evolution.rb', line 14

def dump(options = {})
  classes = options[:classes] || options[:class] || manageable_classes
  basedir = options[:basedir] || 'ogdump'
  
  FileUtils.makedirs(basedir)
  
  for c in [ classes ].flatten      
    Logger.info "Dumping class '#{c}'"
    all = c.all.map { |obj| obj.properties_to_hash }
    File.open("#{basedir}/#{c}.yml", 'w') { |f| f << all.to_yaml }
  end
end

#get_storeObject Also known as: store, conn

Get a store from the pool.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/og/manager.rb', line 61

def get_store
  if Og.thread_safe
    thread = Thread.current

    unless st = thread[:og_store] and st.is_a?(@store_class)
      st = @pool.pop()
      thread[:og_store] = st
    end

    return st
  else
    return @store
  end
end

#load(options = {}) ⇒ Object Also known as: import, evolve

Load Og managed objects from the filesystem. This method can apply optional transformation rules in order to evolve a schema.



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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/og/evolution.rb', line 31

def load(options = {})
  classes = options[:classes] || manageable_classes
  basedir = options[:basedir] || 'ogdump'
  rules = options[:rules] || rules[:evolution] || {}

  classes.each { |c| c.destroy if managed?(c) }
  unmanage_classes(classes)
  manage_classes
  
  for f in Dir["#{basedir}/*.yml"]
    all = YAML.load(File.read(f))
    
    unless all.empty?
      klass = f.split(/\/|\./)[1]
      
      Logger.info "Loading class '#{klass}'"
      
      if krules = rules[klass.to_sym]
        if krules[:self]
          # Class name changed.
          Logger.info "Renaming class '#{klass}' to '#{krules[:self]}'"
          klass = krules[:self]
        end
        
        Logger.info "Evolution transformation will be applied!"
      end      

      klass = constant(klass)
      
      for h in all
        obj = klass.allocate
        obj.assign_with(h)
        if krules
          krules.each do |old, new|
            obj.instance_variable_set "@#{new}", h[old]
          end
        end
        obj.insert
      end
    end
  end
end

#manage(klass) ⇒ Object

Manage a class. Converts the class to an Entity.



99
100
101
102
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
# File 'lib/og/manager.rb', line 99

def manage(klass)
  return if managed?(klass) or klass.ancestors.include?(Unmanageable)

  info = EntityInfo.new(klass)

  # DON'T DO THIS!!!
  klass.module_eval %{
    def ==(other)
      other ? @#{klass.primary_key.symbol} == other.#{klass.primary_key.symbol} : false
    end
  }

  klass.class.send(:attr_accessor, :ogmanager)
  klass.instance_variable_set '@ogmanager', self

  Relation.enchant(klass)

  # ensure that the superclass is managed before the
  # subclass.

  manage(klass.superclass) if manageable?(klass.superclass)

  # FIXME: uggly!
  store.enchant(klass, self); put_store

  # Call special class enchanting code.

  klass.enchant if klass.respond_to?(:enchant)

  @entities[klass] = info
end

#manage_classes(*classes) ⇒ Object Also known as: manage_class

Manage a collection of classes.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/og/manager.rb', line 169

def manage_classes(*classes)
  classes = manageable_classes.flatten # if classes.empty? FIXME!

  classes.each { |c| Relation.resolve_targets(c) }
  classes.each { |c| Relation.resolve_polymorphic_markers(c) }
  classes.each { |c| Relation.resolve_polymorphic_relations(c) }

  # The polymorpic resolution step creates more manageable classes.

  classes = manageable_classes.flatten # if classes.empty? FIXME!

  Logger.debug "Og manageable classes: #{classes.inspect}" if $DBG

  classes.each { |c| Relation.resolve_targets(c) }
  classes.each { |c| Relation.resolve_names(c) }
  classes.each { |c| manage(c) }
=begin
  # gmosx: LETS better investigate this.

  # Checks for obsolete tables lying around in the og store.
  # rp: this shouldn't really be here but I can't think of a better 
  # way to add this functionality.
  
  store = get_store()
  
  if store.respond_to? :unmanaged_tables
    unmanaged_tables = store.unmanaged_tables(self)
    unmanaged_tables.each do |table|

      if @options[:evolve_schema] == true and @options[:evolve_schema_purge_tables] == true
        sql = "DROP TABLE #{table}"
        Logger.debug "Dropping unmanaged database table #{table}"
        store.conn.exec(sql)
      else
        Logger.info "There is a table within the database named '#{table}' that is not managed by an Og class."
      end
    end
  end
=end
end

#manageable?(klass) ⇒ Boolean

Is this class manageable by Og?

Returns:

  • (Boolean)


133
134
135
# File 'lib/og/manager.rb', line 133

def manageable?(klass)
  klass.respond_to?(:properties) and (!klass.properties.empty?) # and klass.ann.self.polymorphic.nil?
end

#manageable_classesObject

Use Ruby’s advanced reflection features to find all manageable classes. Managable are all classes that define Properties.



155
156
157
158
159
160
161
162
163
164
165
# File 'lib/og/manager.rb', line 155

def manageable_classes
  classes = []

  ObjectSpace.each_object(Class) do |c|
    if manageable?(c)
      classes << c
    end
  end

  return classes
end

#managed?(klass) ⇒ Boolean Also known as: entity?

Is the class managed by Og?

Returns:

  • (Boolean)


139
140
141
# File 'lib/og/manager.rb', line 139

def managed?(klass)
  @entities.include?(klass)
end

#managed_classesObject

Returns an array containing all classes managed by this manager.



147
148
149
# File 'lib/og/manager.rb', line 147

def managed_classes
  @entities.map {|e| e[0]}
end

#put_storeObject

Return a store to the pool.



80
81
82
83
84
85
86
87
88
89
# File 'lib/og/manager.rb', line 80

def put_store
  if Og.thread_safe
    thread = Thread.current

    if conn = thread[:og_store]
      thread[:og_store] = nil
      return @pool.push(conn)
    end
  end
end

#resolve_polymorphic(klass) ⇒ Object

Resolve polymorphic relations.



93
94
95
# File 'lib/og/manager.rb', line 93

def resolve_polymorphic(klass)
  Relations.resolve_polymorphic(klass)
end

#unmanage_classes(*classes) ⇒ Object Also known as: unmanage_class



211
212
213
214
215
216
217
# File 'lib/og/manager.rb', line 211

def unmanage_classes(*classes)
  classes = manageable_classes.flatten if classes.empty?

  for c in classes
    @entities.delete_if { |k, v| v.klass == c }
  end
end