comboy-autumn 3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +1192 -0
- data/autumn.gemspec +25 -0
- data/bin/autumn +27 -0
- data/lib/autumn.rb +2 -0
- data/lib/autumn/authentication.rb +290 -0
- data/lib/autumn/channel_leaf.rb +107 -0
- data/lib/autumn/coder.rb +166 -0
- data/lib/autumn/console_boot.rb +9 -0
- data/lib/autumn/ctcp.rb +250 -0
- data/lib/autumn/daemon.rb +207 -0
- data/lib/autumn/datamapper_hacks.rb +290 -0
- data/lib/autumn/foliater.rb +231 -0
- data/lib/autumn/formatting.rb +236 -0
- data/lib/autumn/generator.rb +231 -0
- data/lib/autumn/genesis.rb +191 -0
- data/lib/autumn/inheritable_attributes.rb +162 -0
- data/lib/autumn/leaf.rb +738 -0
- data/lib/autumn/log_facade.rb +49 -0
- data/lib/autumn/misc.rb +87 -0
- data/lib/autumn/script.rb +74 -0
- data/lib/autumn/speciator.rb +165 -0
- data/lib/autumn/stem.rb +919 -0
- data/lib/autumn/stem_facade.rb +176 -0
- data/resources/daemons/Anothernet.yml +3 -0
- data/resources/daemons/AustHex.yml +29 -0
- data/resources/daemons/Bahamut.yml +67 -0
- data/resources/daemons/Dancer.yml +3 -0
- data/resources/daemons/GameSurge.yml +3 -0
- data/resources/daemons/IRCnet.yml +3 -0
- data/resources/daemons/Ithildin.yml +7 -0
- data/resources/daemons/KineIRCd.yml +56 -0
- data/resources/daemons/PTlink.yml +6 -0
- data/resources/daemons/QuakeNet.yml +20 -0
- data/resources/daemons/RFC1459.yml +158 -0
- data/resources/daemons/RFC2811.yml +16 -0
- data/resources/daemons/RFC2812.yml +36 -0
- data/resources/daemons/RatBox.yml +25 -0
- data/resources/daemons/Ultimate.yml +24 -0
- data/resources/daemons/Undernet.yml +6 -0
- data/resources/daemons/Unreal.yml +110 -0
- data/resources/daemons/_Other.yml +7 -0
- data/resources/daemons/aircd.yml +33 -0
- data/resources/daemons/bdq-ircd.yml +3 -0
- data/resources/daemons/hybrid.yml +38 -0
- data/resources/daemons/ircu.yml +67 -0
- data/resources/daemons/tr-ircd.yml +8 -0
- data/skel/Rakefile +135 -0
- data/skel/config/global.yml +2 -0
- data/skel/config/seasons/testing/database.yml +7 -0
- data/skel/config/seasons/testing/leaves.yml +7 -0
- data/skel/config/seasons/testing/season.yml +2 -0
- data/skel/config/seasons/testing/stems.yml +9 -0
- data/skel/leaves/administrator/README +20 -0
- data/skel/leaves/administrator/controller.rb +67 -0
- data/skel/leaves/administrator/views/autumn.txt.erb +1 -0
- data/skel/leaves/administrator/views/reload.txt.erb +11 -0
- data/skel/leaves/insulter/README +17 -0
- data/skel/leaves/insulter/controller.rb +65 -0
- data/skel/leaves/insulter/views/about.txt.erb +1 -0
- data/skel/leaves/insulter/views/help.txt.erb +1 -0
- data/skel/leaves/insulter/views/insult.txt.erb +1 -0
- data/skel/leaves/scorekeeper/README +34 -0
- data/skel/leaves/scorekeeper/config.yml +2 -0
- data/skel/leaves/scorekeeper/controller.rb +104 -0
- data/skel/leaves/scorekeeper/helpers/general.rb +64 -0
- data/skel/leaves/scorekeeper/models/channel.rb +12 -0
- data/skel/leaves/scorekeeper/models/person.rb +14 -0
- data/skel/leaves/scorekeeper/models/pseudonym.rb +11 -0
- data/skel/leaves/scorekeeper/models/score.rb +14 -0
- data/skel/leaves/scorekeeper/tasks/stats.rake +17 -0
- data/skel/leaves/scorekeeper/views/about.txt.erb +1 -0
- data/skel/leaves/scorekeeper/views/change.txt.erb +5 -0
- data/skel/leaves/scorekeeper/views/history.txt.erb +11 -0
- data/skel/leaves/scorekeeper/views/points.txt.erb +5 -0
- data/skel/leaves/scorekeeper/views/usage.txt.erb +1 -0
- data/skel/script/console +34 -0
- data/skel/script/daemon +29 -0
- data/skel/script/destroy +48 -0
- data/skel/script/generate +48 -0
- data/skel/script/server +15 -0
- metadata +170 -0
@@ -0,0 +1,290 @@
|
|
1
|
+
# A set of hacks to make DataMapper play more nicely with classes within
|
2
|
+
# modules.
|
3
|
+
|
4
|
+
module DataMapper # :nodoc:
|
5
|
+
|
6
|
+
#HACK Add module names to auto-generated class names in relationships
|
7
|
+
#
|
8
|
+
# When a class name is automatically inferred from a relationship name (e.g.,
|
9
|
+
# guessing that has_many :widgets refers to a Widget class), it is necessary
|
10
|
+
# to enclose these class names in the same modules as the calling class. For
|
11
|
+
# example, if MyLeaf::Factory has_many :widgets, this hack will ensure the
|
12
|
+
# inferred class name is MyLeaf::Widget, instead of just ::Widget.
|
13
|
+
#
|
14
|
+
# This hack is performed for each of the association types in DataMapper. An
|
15
|
+
# :old_behavior option is given to revert to the unhacked method.
|
16
|
+
|
17
|
+
module Associations # :nodoc:
|
18
|
+
module OneToMany # :nodoc:
|
19
|
+
class << self
|
20
|
+
alias_method :old_setup, :setup
|
21
|
+
def setup(name, model, options={})
|
22
|
+
class_name = options.fetch(:class_name, Extlib::Inflection.classify(name))
|
23
|
+
if not options[:old_behavior] and not class_name.include?('::') then
|
24
|
+
modules = model.to_s.split('::')
|
25
|
+
modules.pop
|
26
|
+
modules << class_name
|
27
|
+
options[:class_name] = modules.join('::')
|
28
|
+
end
|
29
|
+
old_setup(name, model, options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module OneToOne # :nodoc:
|
35
|
+
class << self
|
36
|
+
alias_method :old_setup, :setup
|
37
|
+
def setup(name, model, options={})
|
38
|
+
class_name = options.fetch(:class_name, Extlib::Inflection.classify(name))
|
39
|
+
if not options[:old_behavior] and not class_name.include?('::') then
|
40
|
+
modules = model.to_s.split('::')
|
41
|
+
modules.pop
|
42
|
+
modules << class_name
|
43
|
+
options[:class_name] = modules.join('::')
|
44
|
+
end
|
45
|
+
old_setup(name, model, options)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module ManyToOne # :nodoc:
|
51
|
+
class << self
|
52
|
+
alias_method :old_setup, :setup
|
53
|
+
def setup(name, model, options={})
|
54
|
+
class_name = options.fetch(:class_name, Extlib::Inflection.classify(name))
|
55
|
+
if not options[:old_behavior] and not class_name.include?('::') then
|
56
|
+
modules = model.to_s.split('::')
|
57
|
+
modules.pop
|
58
|
+
modules << class_name
|
59
|
+
options[:class_name] = modules.join('::')
|
60
|
+
end
|
61
|
+
old_setup(name, model, options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#HACK Strip module names when auto-generating table names for has-many-through
|
69
|
+
# relationships.
|
70
|
+
#
|
71
|
+
# By default, DataMapper will not strip module names when creating the join
|
72
|
+
# tables for has-many-through relationships. So, if MyLeaf::Post has and belongs
|
73
|
+
# to many MyLeaf::Category, the join table will be called
|
74
|
+
# "my_leaf/categories_my_leaf/posts", which is clearly an invalid table name.
|
75
|
+
# This hack strips module components from a class name before generating the
|
76
|
+
# join table's name.
|
77
|
+
#
|
78
|
+
# A side effect of this hack is that no two DataMapper models for the same
|
79
|
+
# repository can share the same name, even if they are in separate modules.
|
80
|
+
#
|
81
|
+
# This also fixes a bug that can occur when script/console is launched. The
|
82
|
+
# double assignment of the relationship variable seems to mess up IRb, so it has
|
83
|
+
# been split into two assignments.
|
84
|
+
|
85
|
+
DataMapper::Associations::ManyToMany.module_eval do # :nodoc:
|
86
|
+
def self.setup(name, model, options={})
|
87
|
+
class_name = options.fetch(:class_name, Extlib::Inflection.classify(name))
|
88
|
+
if not options[:old_behavior] and not class_name.include?('::') then
|
89
|
+
modules = model.to_s.split('::')
|
90
|
+
modules.pop
|
91
|
+
modules << class_name
|
92
|
+
options[:class_name] = modules.join('::')
|
93
|
+
end
|
94
|
+
|
95
|
+
assert_kind_of 'name', name, Symbol
|
96
|
+
assert_kind_of 'model', model, DataMapper::Model
|
97
|
+
assert_kind_of 'options', options, Hash
|
98
|
+
|
99
|
+
repository_name = model.repository.name
|
100
|
+
|
101
|
+
model.class_eval <<-EOS, __FILE__, __LINE__
|
102
|
+
def #{name}(query = {})
|
103
|
+
#{name}_association.all(query)
|
104
|
+
end
|
105
|
+
|
106
|
+
def #{name}=(children)
|
107
|
+
#{name}_association.replace(children)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def #{name}_association
|
113
|
+
@#{name}_association ||= begin
|
114
|
+
unless relationship = model.relationships(#{repository_name.inspect})[#{name.inspect}]
|
115
|
+
raise ArgumentError, "Relationship #{name.inspect} does not exist in \#{model}"
|
116
|
+
end
|
117
|
+
association = Proxy.new(relationship, self)
|
118
|
+
parent_associations << association
|
119
|
+
association
|
120
|
+
end
|
121
|
+
end
|
122
|
+
EOS
|
123
|
+
|
124
|
+
opts = options.dup
|
125
|
+
opts.delete(:through)
|
126
|
+
opts[:child_model] ||= opts.delete(:class_name) || Extlib::Inflection.classify(name)
|
127
|
+
opts[:parent_model] = model
|
128
|
+
opts[:repository_name] = repository_name
|
129
|
+
opts[:remote_relationship_name] ||= opts.delete(:remote_name) || Extlib::Inflection.tableize(opts[:child_model])
|
130
|
+
opts[:parent_key] = opts[:parent_key]
|
131
|
+
opts[:child_key] = opts[:child_key]
|
132
|
+
opts[:mutable] = true
|
133
|
+
|
134
|
+
names = [ opts[:child_model].demodulize, opts[:parent_model].name.demodulize ].sort
|
135
|
+
model_name = names.join.gsub("::", "")
|
136
|
+
storage_name = Extlib::Inflection.tableize(Extlib::Inflection.pluralize(names[0]) + names[1])
|
137
|
+
model_module = model.to_s.split('::')
|
138
|
+
model_module.pop
|
139
|
+
model_module = model_module.join('::')
|
140
|
+
model_module = model_module.empty? ? Object : eval("::#{model_module}")
|
141
|
+
|
142
|
+
opts[:near_relationship_name] = Extlib::Inflection.tableize(model_name).to_sym
|
143
|
+
|
144
|
+
model.has(model.n, opts[:near_relationship_name], :old_behavior => true)
|
145
|
+
|
146
|
+
relationship = DataMapper::Associations::RelationshipChain.new(opts)
|
147
|
+
model.relationships(repository_name)[name] = relationship
|
148
|
+
|
149
|
+
unless model_module.const_defined?(model_name)
|
150
|
+
model = DataMapper::Model.new(storage_name)
|
151
|
+
|
152
|
+
model.class_eval <<-EOS, __FILE__, __LINE__
|
153
|
+
def self.name; #{model_name.inspect} end
|
154
|
+
def self.default_repository_name; #{repository_name.inspect} end
|
155
|
+
def self.many_to_many; true end
|
156
|
+
EOS
|
157
|
+
|
158
|
+
names.each do |n|
|
159
|
+
model.belongs_to(Extlib::Inflection.underscore(n).gsub("/", "_").to_sym, :class_name => n)
|
160
|
+
end
|
161
|
+
|
162
|
+
model_module.const_set(model_name, model)
|
163
|
+
end
|
164
|
+
|
165
|
+
relationship
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
#HACK Update methods in RelationshipChain to use the scoped repository.
|
170
|
+
#
|
171
|
+
# This hack will update methods to use the currently-scoped repository, instead
|
172
|
+
# of always using the default repository.
|
173
|
+
|
174
|
+
module DataMapper # :nodoc:
|
175
|
+
module Associations # :nodoc:
|
176
|
+
class RelationshipChain # :nodoc:
|
177
|
+
def near_relationship
|
178
|
+
parent_model.relationships(repository.name)[@near_relationship_name]
|
179
|
+
end
|
180
|
+
|
181
|
+
def remote_relationship
|
182
|
+
return nil unless near_relationship
|
183
|
+
near_relationship.child_model.relationships(repository.name)[@remote_relationship_name] ||
|
184
|
+
near_relationship.child_model.relationships(repository.name)[@remote_relationship_name.to_s.singularize.to_sym]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
DataMapper::Model.class_eval do
|
191
|
+
|
192
|
+
#HACK Determine the child key from the given repository, not the default one.
|
193
|
+
#
|
194
|
+
# Updates this method to use the hacked child_key method.
|
195
|
+
|
196
|
+
def properties_with_subclasses(repository_name = default_repository_name)
|
197
|
+
properties = DataMapper::PropertySet.new
|
198
|
+
([ self ].to_set + (respond_to?(:descendants) ? descendants : [])).each do |model|
|
199
|
+
model.relationships(repository_name).each_value { |relationship| relationship.child_key(repository_name) }
|
200
|
+
model.many_to_one_relationships.each do |relationship| relationship.child_key(repository_name) end
|
201
|
+
model.properties(repository_name).each do |property|
|
202
|
+
properties << property unless properties.has_property?(property.name)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
properties
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
DataMapper::Associations::Relationship.class_eval do
|
210
|
+
|
211
|
+
#HACK Determine the child key from the given repository, not the default one.
|
212
|
+
#
|
213
|
+
# Updates this method to take a repository name. The child key will be
|
214
|
+
# determined from the properties scoped to the given repository.
|
215
|
+
#
|
216
|
+
# The @child_key class variable is changed to a hash that maps repository
|
217
|
+
# names to the appropriate key.
|
218
|
+
|
219
|
+
def child_key(repository_name=nil)
|
220
|
+
repository_name ||= repository.name
|
221
|
+
@child_key ||= Hash.new
|
222
|
+
@child_key[repository_name] ||= begin
|
223
|
+
child_key = nil
|
224
|
+
repository(repository_name).scope do |r|
|
225
|
+
model_properties = child_model.properties(repository_name)
|
226
|
+
|
227
|
+
child_key = parent_key(repository_name).zip(@child_properties || []).map do |parent_property,property_name|
|
228
|
+
# TODO: use something similar to DM::NamingConventions to determine the property name
|
229
|
+
parent_name = Extlib::Inflection.underscore(Extlib::Inflection.demodulize(parent_model.base_model.name))
|
230
|
+
property_name ||= "#{parent_name}_#{parent_property.name}".to_sym
|
231
|
+
|
232
|
+
if model_properties.has_property?(property_name)
|
233
|
+
model_properties[property_name]
|
234
|
+
else
|
235
|
+
options = {}
|
236
|
+
|
237
|
+
[ :length, :precision, :scale ].each do |option|
|
238
|
+
options[option] = parent_property.send(option)
|
239
|
+
end
|
240
|
+
|
241
|
+
# NOTE: hack to make each many to many child_key a true key,
|
242
|
+
# until I can figure out a better place for this check
|
243
|
+
if child_model.respond_to?(:many_to_many)
|
244
|
+
options[:key] = true
|
245
|
+
end
|
246
|
+
|
247
|
+
child_model.property(property_name, parent_property.primitive, options)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
DataMapper::PropertySet.new(child_key)
|
252
|
+
end
|
253
|
+
return @child_key[repository_name]
|
254
|
+
end
|
255
|
+
|
256
|
+
#HACK Determine the parent key from the given repository, not the default one.
|
257
|
+
#
|
258
|
+
# Updates this method to take a repository name. The parent key will be
|
259
|
+
# determined from the properties scoped to the given repository.
|
260
|
+
#
|
261
|
+
# The @parent_key class variable is changed to a hash that maps repository
|
262
|
+
# names to the appropriate key.
|
263
|
+
|
264
|
+
def parent_key(repository_name=nil)
|
265
|
+
repository_name ||= repository.name
|
266
|
+
@parent_key ||= Hash.new
|
267
|
+
@parent_key[repository_name] ||= begin
|
268
|
+
parent_key = nil
|
269
|
+
repository(repository_name).scope do |r|
|
270
|
+
parent_key = if @parent_properties
|
271
|
+
parent_model.properties(repository_name).slice(*@parent_properties)
|
272
|
+
else
|
273
|
+
parent_model.key(repository_name)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
DataMapper::PropertySet.new(parent_key)
|
277
|
+
end
|
278
|
+
return @parent_key[repository_name]
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# Add a method to return all models defined for a repository.
|
283
|
+
|
284
|
+
DataMapper::Repository.class_eval do
|
285
|
+
def models
|
286
|
+
DataMapper::Resource.descendants.select { |cl| not cl.properties(name).empty? or not cl.relationships(name).empty? }
|
287
|
+
#HACK we are assuming that if a model has properties or relationships
|
288
|
+
# defined for a repository, then it must be contextual to that repo
|
289
|
+
end
|
290
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# Defines the Autumn::Foliater class, which instantiates stems and leaves and
|
2
|
+
# keeps watch over their threads.
|
3
|
+
|
4
|
+
module Autumn
|
5
|
+
|
6
|
+
# Loads Stems and Leaves and executes them in their own threads. Manages the
|
7
|
+
# threads and oversees all leaves. This is a singleton class.
|
8
|
+
|
9
|
+
class Foliater
|
10
|
+
include Singleton
|
11
|
+
|
12
|
+
# The Speciator singleton.
|
13
|
+
attr_reader :config
|
14
|
+
# A hash of all Stem instances by their config names.
|
15
|
+
attr_reader :stems
|
16
|
+
# A hash of all Leaf instances by their config names.
|
17
|
+
attr_reader :leaves
|
18
|
+
|
19
|
+
def initialize # :nodoc:
|
20
|
+
@config = Speciator.instance
|
21
|
+
@stems = Hash.new
|
22
|
+
@leaves = Hash.new
|
23
|
+
@ctcp = Autumn::CTCP.new
|
24
|
+
end
|
25
|
+
|
26
|
+
# Loads the config files and their classes, initializes all stems and leaves
|
27
|
+
# and begins the stems' execution processes in their own threads. You must
|
28
|
+
# pass the stem and leaf config hashes (from the stems.yml and leaves.yml
|
29
|
+
# files).
|
30
|
+
#
|
31
|
+
# If +invoke+ is set to false, start_stems will not be called.
|
32
|
+
|
33
|
+
def load(stem_config, leaf_config, invoke=true)
|
34
|
+
load_configs stem_config, leaf_config
|
35
|
+
load_leaf_classes
|
36
|
+
load_leaves
|
37
|
+
load_all_leaf_models
|
38
|
+
load_stems
|
39
|
+
start_stems if invoke
|
40
|
+
end
|
41
|
+
|
42
|
+
# Reloads a leaf while it is running. Re-opens class definition files and
|
43
|
+
# runs them to redefine the classes. Does not work exactly as it should,
|
44
|
+
# but well enough for a rough hot-reload capability.
|
45
|
+
|
46
|
+
def hot_reload(leaf)
|
47
|
+
type = leaf.class.to_s.split('::').first
|
48
|
+
load_leaf_controller type
|
49
|
+
load_leaf_helpers type
|
50
|
+
load_leaf_models leaf
|
51
|
+
load_leaf_views type
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns true if there is at least one stem still running.
|
55
|
+
|
56
|
+
def alive?
|
57
|
+
@stem_threads and @stem_threads.any? { |name, thread| thread.alive? }
|
58
|
+
end
|
59
|
+
|
60
|
+
# This method yields each Stem that was loaded, allowing you to iterate over
|
61
|
+
# each stem. For instance, to take attendance:
|
62
|
+
#
|
63
|
+
# Foliater.instance.each_stem { |stem| stem.message "Here!" }
|
64
|
+
|
65
|
+
def each_stem
|
66
|
+
@leaves.each { |leaf| yield leaf }
|
67
|
+
end
|
68
|
+
|
69
|
+
# This method yields each Leaf subclass that was loaded, allowing you to
|
70
|
+
# iterate over each leaf. For instance, to take attendance:
|
71
|
+
#
|
72
|
+
# Foliater.instance.each_leaf { |leaf| leaf.stems.message "Here!" }
|
73
|
+
|
74
|
+
def each_leaf
|
75
|
+
@leaves.each { |leaf| yield leaf }
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def load_configs(stem_config, leaf_config)
|
81
|
+
leaf_config.each do |name, options|
|
82
|
+
global_config_file = "#{APP_ROOT}/leaves/#{options['class'].snakecase}/config.yml"
|
83
|
+
if File.exist? global_config_file then
|
84
|
+
config.leaf name, YAML.load(File.open(global_config_file))
|
85
|
+
end
|
86
|
+
config.leaf name, options
|
87
|
+
config.leaf name, :logger => LogFacade.new(config.global(:logfile), 'Leaf', name)
|
88
|
+
end
|
89
|
+
stem_config.each do |name, options|
|
90
|
+
config.stem name, options
|
91
|
+
config.stem name, :logger => LogFacade.new(config.global(:logfile), 'Stem', name)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def load_leaf_classes
|
96
|
+
config.all_leaf_classes.each do |type|
|
97
|
+
Object.class_eval "module #{type}; end"
|
98
|
+
|
99
|
+
config.leaf type, :module => Object.const_get(type)
|
100
|
+
|
101
|
+
load_leaf_controller(type)
|
102
|
+
load_leaf_helpers(type)
|
103
|
+
load_leaf_views(type)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def load_leaf_controller(type)
|
108
|
+
controller_file = "#{APP_ROOT}/leaves/#{type.snakecase}/controller.rb"
|
109
|
+
raise "controller.rb file for leaf #{type} not found" unless File.exist? controller_file
|
110
|
+
controller_code = nil
|
111
|
+
begin
|
112
|
+
File.open("#{APP_ROOT}/leaves/#{type.snakecase}/controller.rb", 'r') { |f| controller_code = f.read }
|
113
|
+
rescue Errno::ENOENT
|
114
|
+
raise "controller.rb file for leaf #{type} not found"
|
115
|
+
end
|
116
|
+
config.leaf(type, :module).module_eval controller_code
|
117
|
+
end
|
118
|
+
|
119
|
+
def load_leaf_helpers(type)
|
120
|
+
mod = config.leaf(type, :module)
|
121
|
+
helper_code = nil
|
122
|
+
Dir.glob("#{APP_ROOT}/leaves/#{type.snakecase}/helpers/*.rb").each do |helper_file|
|
123
|
+
File.open(helper_file, 'r') { |f| helper_code = f.read }
|
124
|
+
mod.module_eval helper_code
|
125
|
+
end
|
126
|
+
|
127
|
+
leaf_class = nil
|
128
|
+
begin
|
129
|
+
leaf_class = mod.const_get('Controller')
|
130
|
+
rescue NameError
|
131
|
+
raise NameError, "Couldn't find Controller class for leaf #{type}"
|
132
|
+
end
|
133
|
+
|
134
|
+
config.leaf type, :helpers => Set.new
|
135
|
+
mod.constants.select { |const_name| const_name =~ /Helper$/ }.map { |helper_name| mod.const_get helper_name }.each do |helper|
|
136
|
+
config.leaf(type, :helpers) << helper
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def load_leaf_views(type)
|
141
|
+
views = Hash.new
|
142
|
+
view_text = nil
|
143
|
+
Dir.glob("#{APP_ROOT}/leaves/#{type.snakecase}/views/*.txt.erb").each do |view_file|
|
144
|
+
view_name = File.basename(view_file).match(/^(.+)\.txt\.erb$/)[1]
|
145
|
+
File.open(view_file, 'r') { |f| view_text = f.read }
|
146
|
+
views[view_name] = view_text
|
147
|
+
end
|
148
|
+
config.leaf type, :views => views
|
149
|
+
end
|
150
|
+
|
151
|
+
def load_leaves
|
152
|
+
config.each_leaf do |name, options|
|
153
|
+
options = config.options_for_leaf(name)
|
154
|
+
options[:root] = "#{config.global :root}/leaves/#{options[:class].snakecase}"
|
155
|
+
begin
|
156
|
+
leaf_class = options[:module].const_get('Controller')
|
157
|
+
rescue NameError
|
158
|
+
raise NameError, "Couldn't find Controller class for leaf #{name}"
|
159
|
+
end
|
160
|
+
@leaves[name] = leaf_class.new(options)
|
161
|
+
formatter = Autumn::Formatting.const_get options[:formatter].to_sym if options[:formatter] and (Autumn::Formatting.constants.include? options[:formatter] or Autumn::Formatting.constants.include? options[:formatter].to_sym)
|
162
|
+
formatter ||= Autumn::Formatting::DEFAULT
|
163
|
+
@leaves[name].extend formatter
|
164
|
+
options[:helpers].each { |helper| @leaves[name].extend helper }
|
165
|
+
# extend the formatter first so helper methods override its methods if necessary
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def load_all_leaf_models
|
170
|
+
@leaves.each { |name, instance| load_leaf_models instance }
|
171
|
+
end
|
172
|
+
|
173
|
+
def load_leaf_models(leaf)
|
174
|
+
model_code = nil
|
175
|
+
mod = config.leaf(leaf.options[:class], :module)
|
176
|
+
leaf.database do
|
177
|
+
Dir.glob("#{APP_ROOT}/leaves/#{leaf.options[:class].snakecase}/models/*.rb").each do |model_file|
|
178
|
+
File.open(model_file, 'r') { |f| model_code = f.read }
|
179
|
+
mod.module_eval model_code
|
180
|
+
end
|
181
|
+
# Need to manually set the table names of the models because we loaded
|
182
|
+
# them inside a module
|
183
|
+
unless $NO_DATABASE
|
184
|
+
mod.constants.map { |const_name| mod.const_get(const_name) }.select { |const| const.ancestors.include? DataMapper::Resource }.each do |model|
|
185
|
+
model.storage_names[leaf.database_name] = model.to_s.demodulize.snakecase.pluralize
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def load_stems
|
192
|
+
config.each_stem do |name, options|
|
193
|
+
options = config.options_for_stem(name)
|
194
|
+
server = options[:server]
|
195
|
+
nick = options[:nick]
|
196
|
+
|
197
|
+
@stems[name] = Stem.new(server, nick, options)
|
198
|
+
leaves = options[:leaves]
|
199
|
+
leaves ||= [ options[:leaf] ]
|
200
|
+
leaves.each do |leaf|
|
201
|
+
raise "Unknown leaf #{leaf} in configuration for stem #{name}" unless @leaves[leaf]
|
202
|
+
@stems[name].add_listener @leaves[leaf]
|
203
|
+
@stems[name].add_listener @ctcp
|
204
|
+
#TODO a configurable way of specifying listeners to add by default
|
205
|
+
@leaves[leaf].stems << @stems[name]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def start_stems
|
211
|
+
@leaves.each { |name, leaf| leaf.preconfigure }
|
212
|
+
@leaves.each { |name, leaf| leaf.will_start_up }
|
213
|
+
@stem_threads = Hash.new
|
214
|
+
config.each_stem do |name, options|
|
215
|
+
@stem_threads[name] = Thread.new(@stems[name], Thread.current) do |stem, parent_thread|
|
216
|
+
# The thread will run the stem until it exits, then inform the main
|
217
|
+
# thread that it has exited. When the main thread wakes, it checks if
|
218
|
+
# all stems have terminated; if so, it terminates itself.
|
219
|
+
begin
|
220
|
+
stem.start
|
221
|
+
rescue
|
222
|
+
options[:logger].fatal $!
|
223
|
+
ensure
|
224
|
+
parent_thread.wakeup # Schedule the parent thread to wake up after this thread finishes
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|