Class: Stratagem::Model::Component::Model

Inherits:
Base show all
Defined in:
lib/stratagem/model/components/model.rb

Constant Summary collapse

ModificationMethods =
['update','create','new']

Constants included from ParseUtil

ParseUtil::RUBY_OUTPUT_REGEX, ParseUtil::RUBY_REGEX

Instance Attribute Summary collapse

Attributes inherited from Base

#app_model, #klass, #parse_tree, #path, #source

Instance Method Summary collapse

Methods inherited from Base

#==, load_all, logger, #logger, #name

Methods included from ParseUtil

find_classes, #gsub_ruby_blocks, qualified_class_name, #ruby_blocks, #ruby_output_blocks

Constructor Details

#initialize(*args) ⇒ Model

Returns a new instance of Model.



11
12
13
14
15
16
# File 'lib/stratagem/model/components/model.rb', line 11

def initialize(*args)
  super(*args)
  load_attributes
  @model_assignable_attributes = find_assignable_attributes
  @model_instance_methods = self.klass.instance_methods
end

Instance Attribute Details

#model_accessible_attributesObject (readonly)

Returns the value of attribute model_accessible_attributes.



6
7
8
# File 'lib/stratagem/model/components/model.rb', line 6

def model_accessible_attributes
  @model_accessible_attributes
end

#model_assignable_attributesObject (readonly)

fields / methods that can be manipulated in Model.new(..)



4
5
6
# File 'lib/stratagem/model/components/model.rb', line 4

def model_assignable_attributes
  @model_assignable_attributes
end

#model_attributesObject (readonly)

database attributes that the model contains



3
4
5
# File 'lib/stratagem/model/components/model.rb', line 3

def model_attributes
  @model_attributes
end

#model_internal_attributesObject (readonly)

Returns the value of attribute model_internal_attributes.



5
6
7
# File 'lib/stratagem/model/components/model.rb', line 5

def model_internal_attributes
  @model_internal_attributes
end

#model_referenced_byObject

other classes / libraries that reference this model



7
8
9
# File 'lib/stratagem/model/components/model.rb', line 7

def model_referenced_by
  @model_referenced_by
end

Instance Method Details

#association_match?(association_name, desired_model) ⇒ Boolean

iterate model’s associations to see if there’s an association with the specific name and class. This is used as an aproximation to determine whether or not a node in the parse tree could be talking about a specific relationship

Returns:

  • (Boolean)


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/stratagem/model/components/model.rb', line 25

def association_match?(association_name, desired_model)
  @association_matches ||= {}
  @association_matches[association_name+"_"+desired_model.klass.name] ||= begin
    klass.stratagem.relations.select {|relation|  
      (relation.name.to_sym == association_name.to_sym) && (relation.klass == desired_model.klass)
    }.map {|relation| 
      relation.klass.name 
    }.first
  rescue
    Rails.logger.error("unable to lookup associations on #{self.klass.name} not active record model?")
    Rails.logger.error($!)
    false
  end
  @association_matches[association_name+"_"+desired_model.klass.name]
end

#exportObject

References to the find and find_x methods on the model def references_to_finders()

references = []
method = nil
app_model.controllers.each {|controller|
  controller.parse_tree.walk {|parent,i,subi,node|
    case node
    when RedParse::MethodNode
      method = node
    when RedParse::CallNode
      if (!(parent.kind_of?(RedParse::AssignNode)) && (node.receiver) && (node.receiver.to_s == klass.name))
        references << ControllerModelReference.new(controller, method.name, node.name, node)
      end
    end

    case parent
    when RedParse::AssignNode
      # p parent
      begin
        if (node.kind_of?(RedParse::CallNode) && (node.receiver) && (node.receiver.name == klass.name))
          references << ControllerModelReference.new(controller, method.name, node.name, node)
        end
      rescue
        puts $!.message
        puts $!.backtrace
        # p parent
      end
    end
    true
  }
}
references

end



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/stratagem/model/components/model.rb', line 130

def export
  adapters = stratagem? ? klass.stratagem.callbacks.map {|c| c.class.name } : []
  {
    :external_id => self.object_id,

    :model_path => @path.gsub(RAILS_ROOT+'/', ''), 
    :model_class_name => @klass.name, 
    :model_superclass => @klass.methods.include?(:superclass) ? @klass.superclass.name : nil, 
    :model_included_modules => @klass.included_modules.map {|m| m.name},
    :model_attributes => @model_attributes,
    :model_foreign_keys => @model_foreign_keys,
    :model_assignable_attributes => @model_assignable_attributes,
    :model_internal_attributes => @model_internal_attributes,
    :model_accessible_attributes => @model_accessible_attributes,
    :model_whitelists_attributes => stratagem? ? @klass.stratagem.whitelists_attributes? : nil,
    :model_blacklists_attributes => stratagem? ? @klass.stratagem.blacklists_attributes? : nil,
    :model_instance_methods => @model_instance_methods,

    :relations_attributes => relations.map {|r| r.export },
  }
end

#find_assignable_attributesObject

TODO - refactor into model persistence strategy



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/stratagem/model/components/model.rb', line 55

def find_assignable_attributes
  assignable_attributes = []

  # Using instance methods allows us to check for functions that would be mass assignable
  # in addition to Active Record attributes
  begin
    if (stratagem?)
      object = klass.new # used to look up metadata
      if (object)
        methods = nil
        if (klass.stratagem.unaccessible_attributes)
          assignable_attributes = (klass.stratagem.attribute_names - klass.stratagem.unaccessible_attributes).to_a
        else
          methods = klass.instance_methods + object.stratagem.attribute_names
          methods.each {|method|
            param_name = method.to_s.gsub('=','').to_sym
            val = rand(100)
            params = { param_name => val }
            begin
              instance = klass.new(params)
              assignable_attributes << param_name.to_sym
            rescue ActiveRecord::UnknownAttributeError
              # the attribute is not mass assignable
            rescue
              # the function was called but an error was raised
              assignable_attributes << param_name.to_sym
            end
          }
        end
      end
      assignable_attributes.uniq
    end
  rescue
    puts "Unable to analyze model #{klass.name}"
    puts $!.message
   puts $!.backtrace
    # raise $!
    []
  end
end

#load_attributesObject



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/stratagem/model/components/model.rb', line 41

def load_attributes
  @model_attributes = {}
  if (stratagem?)
    object = klass.new # used to look up metadata
    object.stratagem.attribute_names.each {|attribute|
      @model_attributes[attribute.to_sym] = object.stratagem.attribute_type(attribute.to_sym)
    }
    @model_foreign_keys = object.stratagem.foreign_keys
    @model_internal_attributes = object.stratagem.internal_attributes
    @model_accessible_attributes = object.stratagem.attribute_names - object.stratagem.unaccessible_attributes
  end
end

#stratagem?Boolean

Returns:

  • (Boolean)


18
19
20
# File 'lib/stratagem/model/components/model.rb', line 18

def stratagem?
  klass.methods_include?(:stratagem)
end