Class: DataShift::MethodDictionary

Inherits:
Object
  • Object
show all
Extended by:
Logging
Includes:
Logging
Defined in:
lib/datashift/method_dictionary.rb

Class Method Summary collapse

Methods included from Logging

logdir, logger

Class Method Details

.add(klass, operator, type = :assignment) ⇒ Object



90
91
92
93
94
95
# File 'lib/datashift/method_dictionary.rb', line 90

def self.add( klass, operator, type = :assignment)
  method_details_mgr = get_method_details_mgr( klass )
  md = MethodDetail.new(operator, klass, operator, type)
  method_details_mgr <<  md
  return md
end

.assignmentsObject



248
249
250
251
# File 'lib/datashift/method_dictionary.rb', line 248

def self.assignments
  @assignments ||= {}
  @assignments
end

.assignments_for(klass) ⇒ Object



271
272
273
# File 'lib/datashift/method_dictionary.rb', line 271

def self.assignments_for(klass)
  assignments[klass] || []
end

.belongs_toObject



233
234
235
236
# File 'lib/datashift/method_dictionary.rb', line 233

def self.belongs_to
  @belongs_to ||={}
  @belongs_to
end

.belongs_to_for(klass) ⇒ Object



259
260
261
# File 'lib/datashift/method_dictionary.rb', line 259

def self.belongs_to_for(klass)
  belongs_to[klass] || []
end

.build_method_details(klass, options = {}) ⇒ Object

Build a thorough and usable picture of the operators by building dictionary of our MethodDetail objects which can be used to import/export data to objects of type ‘klass’ Subsequent calls with same class will return existign mapping To over ride this behaviour, supply :force => true to force regeneration



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
# File 'lib/datashift/method_dictionary.rb', line 102

def self.build_method_details( klass, options = {} )

  return method_details_mgrs[klass] if(method_details_mgrs[klass] && !options[:force])

  method_details_mgr = MethodDetailsManager.new( klass )
  
  method_details_mgrs[klass] = method_details_mgr
        
  assignments_for(klass).each do |n|
    method_details_mgr << MethodDetail.new(n, klass, n, :assignment, column_types[klass])
  end
    
  has_one_for(klass).each do |n|
    method_details_mgr << MethodDetail.new(n, klass, n, :has_one)
  end
    
  has_many_for(klass).each do |n|
    method_details_mgr << MethodDetail.new(n, klass, n, :has_many)
  end
    
  belongs_to_for(klass).each do |n|
    method_details_mgr << MethodDetail.new(n, klass, n, :belongs_to)
  end
  
  method_details_mgr
  
end

.clearObject



209
210
211
212
213
214
215
216
# File 'lib/datashift/method_dictionary.rb', line 209

def self.clear
  belongs_to.clear
  has_many.clear
  assignments.clear
  column_types.clear
  has_one.clear
  method_details_mgrs.clear
end

.column_key(klass, column) ⇒ Object



218
219
220
# File 'lib/datashift/method_dictionary.rb', line 218

def self.column_key(klass, column)
  "#{klass.name}:#{column}"
end

.column_type_for(klass, column) ⇒ Object



275
276
277
# File 'lib/datashift/method_dictionary.rb', line 275

def self.column_type_for(klass, column)
  column_types[klass] ?  column_types[klass][column] : []
end

.column_typesObject



253
254
255
256
# File 'lib/datashift/method_dictionary.rb', line 253

def self.column_types
  @column_types ||= {}
  @column_types  
end

.dump(klass) ⇒ Object

Dump out all available operators



150
151
152
153
# File 'lib/datashift/method_dictionary.rb', line 150

def self.dump( klass )
  method_details_mgr = get_method_details_mgr( klass )
  #TODO
end

.find_method_detail(klass, external_name, conditions = nil) ⇒ Object

For a client supplied name/header - find the operator i.e appropriate call + column type

e.g Given users entry in spread sheet check for pluralization, missing underscores etc

If not nil, returned method can be used directly in for example klass.new.send( call, .… )



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/datashift/method_dictionary.rb', line 162

def self.find_method_detail( klass, external_name, conditions = nil )

  method_details_mgr = get_method_details_mgr( klass )
   
  # first try for an exact match across all association types
  MethodDetail::supported_types_enum.each do |t|
    method_detail = method_details_mgr.find(external_name, t)
    return method_detail.clone if(method_detail)
  end  
          
  # Now try various alternatives of the name
  substitutions(external_name).each do |n|    
    # Try each association type, returning first that contains matching operator with name n    
    MethodDetail::supported_types_enum.each do |t|
      method_detail = method_details_mgr.find(n, t)
      return method_detail.clone if(method_detail)
    end  
  end

  nil
end

.find_method_detail_if_column(klass, external_name) ⇒ Object

Assignments can contain things like delegated methods, this returns a matching method details only when a true database column



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/datashift/method_dictionary.rb', line 186

def self.find_method_detail_if_column( klass, external_name )

  method_details_mgr = get_method_details_mgr( klass )
  
  # first try for an exact match across all association types
  MethodDetail::supported_types_enum.each do |t|
    method_detail = method_details_mgr.find(external_name, t)
    return method_detail.clone if(method_detail && method_detail.col_type) 
  end  
          
  # Now try various alternatives
  substitutions(external_name).each do |n|    
    # Try each association type, returning first that contains matching operator with name n    
    MethodDetail::supported_types_enum.each do |t|
      method_detail = method_details_mgr.find(n, t)
      return method_detail.clone if(method_detail && method_detail.col_type) 
    end  
  end

  nil
end

.find_operators(klass, options = {}) ⇒ Object

Create simple picture of all the operator names for assignment available on an AR model, grouped by type of association (includes belongs_to and has_many which provides both << and = ) Options:

:reload => clear caches and re-perform  lookup
:instance_methods => if true include instance method type 'setters' as well as model's pure columns


27
28
29
30
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
73
74
75
# File 'lib/datashift/method_dictionary.rb', line 27

def self.find_operators(klass, options = {} )
  
  raise "Cannot find operators supplied klass nil #{klass}" if(klass.nil?)

  logger.debug("MethodDictionary - building operators information for #{klass}")

  # Find the has_many associations which can be populated via <<
  if( options[:reload] || has_many[klass].nil? )
    has_many[klass] = klass.reflect_on_all_associations(:has_many).map { |i| i.name.to_s }
    klass.reflect_on_all_associations(:has_and_belongs_to_many).inject(has_many[klass]) { |x,i| x << i.name.to_s }
  end

  # Find the belongs_to associations which can be populated via  Model.belongs_to_name = OtherArModelObject
  if( options[:reload] || belongs_to[klass].nil? )
    belongs_to[klass] = klass.reflect_on_all_associations(:belongs_to).map { |i| i.name.to_s }
  end

  # Find the has_one associations which can be populated via  Model.has_one_name = OtherArModelObject
  if( options[:reload] || has_one[klass].nil? )
    has_one[klass] = klass.reflect_on_all_associations(:has_one).map { |i| i.name.to_s }
  end

  # Find the model's column associations which can be populated via xxxxxx= value
  # Note, not all reflections return method names in same style so we convert all to
  # the raw form i.e without the '='  for consistency 
  if( options[:reload] || assignments[klass].nil? )
 
    assignments[klass] = klass.column_names  
     
    # get into consistent format with other assignments names i.e remove the = for now
    assignments[klass] += setters(klass).map{|i| i.gsub(/=/, '')} if(options[:instance_methods])
       
    # Now remove all the associations
    assignments[klass] -= has_many[klass]   if(has_many[klass])
    assignments[klass] -= belongs_to[klass] if(belongs_to[klass])
    assignments[klass] -= has_one[klass]    if(has_one[klass])
     
    # TODO remove assignments with id
    # assignments => tax_id  but already in belongs_to => tax
    
    assignments[klass].uniq!

    assignments[klass].each do |assign|
      column_types[klass] ||= {}
      column_def = klass.columns.find{ |col| col.name == assign }
      column_types[klass].merge!( assign => column_def) if column_def
    end
  end
end

.for?(klass) ⇒ Boolean

Return true if dictionary has been populated for klass

Returns:

  • (Boolean)


16
17
18
19
# File 'lib/datashift/method_dictionary.rb', line 16

def self.for?(klass)
  any = has_many[klass] || belongs_to[klass] || has_one[klass] || assignments[klass]
  return any != nil
end

.get_method_details_mgr(klass) ⇒ Object



222
223
224
# File 'lib/datashift/method_dictionary.rb', line 222

def self.get_method_details_mgr( klass )
  method_details_mgrs[klass] || MethodDetailsManager.new( klass )
end

.has_manyObject



238
239
240
241
# File 'lib/datashift/method_dictionary.rb', line 238

def self.has_many
  @has_many ||= {}
  @has_many
end

.has_many_for(klass) ⇒ Object



263
264
265
# File 'lib/datashift/method_dictionary.rb', line 263

def self.has_many_for(klass)
  has_many[klass] || []
end

.has_oneObject



243
244
245
246
# File 'lib/datashift/method_dictionary.rb', line 243

def self.has_one
  @has_one ||= {}
  @has_one
end

.has_one_for(klass) ⇒ Object



267
268
269
# File 'lib/datashift/method_dictionary.rb', line 267

def self.has_one_for(klass)
  has_one[klass] || []
end

.method_details_mgrsObject

Store a Mgr per mapped klass



228
229
230
231
# File 'lib/datashift/method_dictionary.rb', line 228

def self.method_details_mgrs
  @method_details_mgrs ||= {}
  @method_details_mgrs
end

.setters(klass) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/datashift/method_dictionary.rb', line 77

def self.setters( klass )
      
  # N.B In 1.8 these return strings, in 1.9 symbols.
  # map everything to strings a
  #setters = klass.accessible_attributes.sort.collect( &:to_s )
  
  # remove methodsa that start with '_'
  @keep_only_pure_setters ||= Regexp.new(/^[a-zA-Z]\w+=/)
  
  setters = klass.instance_methods.grep(@keep_only_pure_setters).sort.collect( &:to_s )
  setters.uniq
end

.substitutions(external_name) ⇒ Object

TODO - check out regexp to do this work better plus Inflections ?? Want to be able to handle any of [“Count On hand”, ‘count_on_hand’, “Count OnHand”, “COUNT ONHand” etc]



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/datashift/method_dictionary.rb', line 132

def self.substitutions(external_name)
  name = external_name.to_s
  
  [
    name.downcase,
    name.tableize,
    name.gsub(' ', '_'),
    name.gsub(' ', '_').downcase,
    name.gsub(/(\s+)/, '_').downcase,
    name.gsub(' ', ''),
    name.gsub(' ', '').downcase,
    name.gsub(' ', '_').underscore
  ]
end