lib/goaloc/goal.rb in mattknox-goaloc-0.4.2 vs lib/goaloc/goal.rb in mattknox-goaloc-0.4.4
- old
+ new
@@ -1,5 +1,10 @@
+# This is the core of goaloc: the goal object.
+# A goal object is intended to be a vertical slice of an MVC app, with information about its model, views,
+# controllers, and routes. It needs to be extended so that it can handle generating plugins/stylesheets/js/etc.
+# Generators call a number of methods on goals that allow them to hook into their code generation process and
+# customize the output.
class Goal
attr_reader :name
attr_accessor :associations, :validations, :fields, :options, :routes, :foreign_keys
def initialize(name, route = [])
@@ -11,21 +16,22 @@
self.options = { }
self.routes = [] # of the form [:classname, [:otherclass, :classname], ...]
Object.const_set self.cs, self
end
- # here are a list of name-ish methods
+ # === here are a list of name-ish methods
+ # This returns the name of the foreign key used to refer to this goal.
def foreign_key
self.name + "_id"
end
def s; self.name; end
def p; self.name.pluralize; end
def cs; self.name.camelize.singularize; end
def cp; self.name.camelize.pluralize; end
- # stuff used to introspect on the goal
+ # === stuff used to introspect on the goal
# thanks to Josh Ladieu for this: it's the array of things needed to get to an instance of this class, if there is a unique set.
def resource_tuple # this returns the minimal route to this goal, or nothing, if there is no unambiguous minimal route
routelist = self.routes.sort { |x, y| x.length <=> y.length }
if routelist.length == 1 #TODO: maybe should deal with a case where there's a simplest route that all the others contain.
routelist.first
@@ -44,45 +50,49 @@
def ivar_tuple
self.resource_tuple.to_a.map { |x| "@" + x.to_s.underscore.singularize }
end
+ # this is intended to grab the list of elements needed to populate a form_for,
+ # propagated back from the named end_element
+ # so for [:users, [:posts, [:comments, :ratings]]] in the rating form it would be:
+ # form.comment.post.user, form.comment.post, form.comment, form
def backvar_tuple(end_element = "form")
- # this is intended to grab the list of elements needed to populate a form_for,
- # propagated back from the named end_element
- # so for [:users, [:posts, [:comments, :ratings]]] in the rating form it would be:
- # form.comment.post.user, form.comment.post, form.comment, form
self.resource_tuple[0..-2].map {|sym| sym.to_s.singularize }.reverse.inject([end_element]) {|acc, x| acc.unshift(acc.first + "." + x )}
end
+ # this returns the set of resources that are nested under this resource.
def nested_resources
- APP.goals.reject { |k, v| v.routes != [(self.resource_tuple + [k.pluralize.to_sym])] } # TODO: make this work with singular resources
+ APP.goals.reject { |k, v| (v.routes != [(self.resource_tuple + [k.pluralize.to_sym])]) and (v.routes != [(self.resource_tuple + [k.singularize.to_sym])]) } # TODO: see if this can be cleaned up a bit.
end
# validations
def validates(validation_type, field, opts = { })
self.validations << opts.merge({ :val_type => validation_type, :field => field})
end
- # association stuff
+ # === association stuff
+ # set a belongs_to association
def belongs_to(goal, options = { })
-# self.fields[goal.foreign_key] = "references"
self.foreign_keys[goal.foreign_key] = "references"
self.validates(:presence_of, goal.foreign_key)
self.associate(:belongs_to, goal, options)
end
+ # sets a has-many association from this goal to the target goal. Also sets up a returning belongs_to association
def has_many(goal, options = { })
goal.belongs_to(self) unless options[:skip_belongs_to]
self.associate(:has_many, goal, options)
end
+ # sets up the little-used has-one association, and the returning belongs_to.
def has_one(goal, options = { })
goal.belongs_to(self) unless options[:skip_belongs_to]
self.associate(:has_one, goal, options)
end
+ # this sets a has-many through association, and by default, the reciprocal hmt.
def hmt(goal, options)
thru = options[:through]
self.has_many(thru)
self.has_many(goal, :through => thru, :skip_belongs_to => true)
unless options[:bidi] == false
@@ -98,12 +108,13 @@
def default_assoc_name(assoc_type)
:has_many == assoc_type ? name.pluralize : name
end
+ # this method adds attributes to the goal, in the format name1:type1 name2:type2. Type names have unsociable chars like . , - etc. stripped
def add_attrs(*args)
if args.is_a? Array and args.length == 1
- args.first.split.each do |s|
+ args.first.gsub(/[-.,]/, '').split.each do |s|
name, field_type = s.split(":")
add_attr(name, field_type)
end
end
end