ar_loader 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,139 +1,140 @@
1
- # Copyright:: (c) Autotelik Media Ltd 2011
2
- # Author :: Tom Statter
3
- # Date :: Aug 2010
4
- # License:: MIT
5
- #
6
- # Details:: This class provides information and access to the individual methods
7
- # on an AR model. Populated by, and coupled with MethodMapper,
8
- # which does the model interrogation work.
9
- # Enables 'loaders' to iterate over the MethodMapper results set,
10
- # and assign values to AR object, without knowing anything about that receiving object.
11
- #
12
- # =>
13
- require 'to_b'
14
-
15
- class MethodDetail
16
-
17
- # When looking up an association, try each of these in turn till a match
18
- # i.e find_by_name .. find_by_title and so on
19
- @@insistent_find_by_list ||= [:id, :name, :title]
20
-
21
- attr_accessor :klass, :name, :assignment, :col_type
22
- attr_accessor :has_many, :has_many_class_name, :has_many_class
23
- attr_accessor :belongs_to, :belongs_to_class_name, :belongs_to_class
24
-
25
- @@default_values = {}
26
- @@prefixes = {}
27
-
28
-
29
- def initialize(klass, name, assignment, belongs_to, has_many, col_type = nil)
30
- @klass, @name, @assignment, @has_many, @belongs_to, @col_type = klass, name, assignment, has_many, belongs_to, col_type
31
-
32
- if(@has_many)
33
- begin
34
- @has_many_class = Kernel.const_get(@has_many.classify)
35
- @has_many_class_name = @has_many.classify
36
- rescue
37
- end
38
- end
39
-
40
- if(@belongs_to)
41
- begin
42
- @belongs_to_class = Kernel.const_get(@belongs_to.classify)
43
- @belongs_to_class_name = @belongs_to.classify
44
- rescue
45
- # TODO - try other forms of the name, set to nil, or bomb out ?
46
- end
47
- end
48
- end
49
-
50
- def assign( record, value )
51
- #puts "DEBUG: assign: [#{@name}]"
52
-
53
- data = value
54
-
55
- if(@@default_values[@name])
56
- puts "WARNING nil value supplied for [#{@name}] - Using default : [#{@@default_values[@name]}]"
57
- data = @@default_values[@name]
58
- else
59
- puts "WARNING nil value supplied for [#{@name}] - No default"
60
- end if(data.nil?)
61
-
62
- data = "#{@@prefixes[@name]}#{data}" if(@@prefixes[@name])
63
-
64
- if( @belongs_to )
65
-
66
- #puts "DEBUG : BELONGS_TO #{@belongs_to} - Lookup #{data} in DB"
67
- insistent_belongs_to(record, data)
68
-
69
- elsif( @assignment && @col_type )
70
- #puts "DEBUG : COl TYPE defined for #{@name} : #{@assignment} => #{data} #{@col_type.inspect}"
71
- record.send( @assignment, @col_type.type_cast( data ) )
72
-
73
- elsif( @assignment )
74
- #puts "DEBUG : No COL TYPE found for #{@name} : #{@assignment} => #{data}"
75
- insistent_assignment(record, data)
76
- end
77
- end
78
-
79
- # Attempt to find the associated object via id, name, title ....
80
- def insistent_belongs_to( record, value )
81
-
82
- @@insistent_find_by_list.each do |x|
83
- begin
84
- item = @belongs_to_class.send( "find_by_#{x}", value)
85
- if(item)
86
- record.send("#{@belongs_to}=", item)
87
- break
88
- end
89
- rescue => e
90
- puts e.inspect
91
- if(x == @@insistent_method_list.last)
92
- puts "I'm sorry I have failed to assign [#{value}] to #{@assignment}"
93
- raise "I'm sorry I have failed to assign [#{value}] to #{@assignment}" unless value.nil?
94
- end
95
- end
96
- end
97
- end
98
-
99
- def insistent_assignment( record, value )
100
- @@insistent_method_list ||= [:to_i, :to_f, :to_b]
101
- begin
102
- record.send(@assignment, value)
103
- rescue => e
104
- puts e.inspect
105
- @@insistent_method_list.each do |f|
106
- begin
107
- record.send(@assignment, value.send( f) )
108
- break
109
- rescue => e
110
- #puts "DEBUG: insistent_assignment: #{e.inspect}"
111
- if f == @@insistent_method_list.last
112
- puts "I'm sorry I have failed to assign [#{value}] to #{@assignment}"
113
- raise "I'm sorry I have failed to assign [#{value}] to #{@assignment}" unless value.nil?
114
- end
115
- end
116
- end
117
- end
118
- end
119
-
120
- def self.set_default_value( name, value )
121
- @@default_values[name] = value
122
- end
123
-
124
- def self.default_value(name)
125
- @@default_values[name]
126
- end
127
-
128
- def self.set_prefix( name, value )
129
- @@prefixes[name] = value
130
- end
131
-
132
- def self.default_value(name)
133
- @@prefixes[name]
134
- end
135
-
136
- def pp
137
- "#{@name} => #{@assignment} : #{@has_many}"
138
- end
139
- end
1
+ # Copyright:: (c) Autotelik Media Ltd 2011
2
+ # Author :: Tom Statter
3
+ # Date :: Aug 2010
4
+ # License:: MIT
5
+ #
6
+ # Details:: This class provides information and access to the individual methods
7
+ # on an AR model. Populated by, and coupled with MethodMapper,
8
+ # which does the model interrogation work.
9
+ # Enables 'loaders' to iterate over the MethodMapper results set,
10
+ # and assign values to AR object, without knowing anything about that receiving object.
11
+ #
12
+ # =>
13
+ require 'to_b'
14
+
15
+ class MethodDetail
16
+
17
+ # When looking up an association, try each of these in turn till a match
18
+ # i.e find_by_name .. find_by_title and so on
19
+ @@insistent_find_by_list ||= [:id, :name, :title]
20
+
21
+ attr_accessor :klass, :name, :assignment, :col_type
22
+ attr_accessor :has_many, :has_many_class_name, :has_many_class
23
+ attr_accessor :belongs_to, :belongs_to_class_name, :belongs_to_class
24
+
25
+ @@default_values = {}
26
+ @@prefixes = {}
27
+
28
+
29
+ def initialize(klass, name, assignment, belongs_to, has_many, col_type = nil)
30
+ @klass, @name, @assignment, @has_many, @belongs_to, @col_type = klass, name, assignment, has_many, belongs_to, col_type
31
+
32
+ if(@has_many)
33
+ begin
34
+ @has_many_class = Kernel.const_get(@has_many.classify)
35
+ @has_many_class_name = @has_many.classify
36
+ rescue
37
+ end
38
+ end
39
+
40
+ if(@belongs_to)
41
+ begin
42
+ @belongs_to_class = Kernel.const_get(@belongs_to.classify)
43
+ @belongs_to_class_name = @belongs_to.classify
44
+ rescue
45
+ # TODO - try other forms of the name, set to nil, or bomb out ?
46
+ end
47
+ end
48
+ end
49
+
50
+ def assign( record, value )
51
+ #puts "DEBUG: assign: [#{@name}]"
52
+
53
+ data = value
54
+
55
+ if(@@default_values[@name])
56
+ puts "WARNING nil value supplied for [#{@name}] - Using default : [#{@@default_values[@name]}]"
57
+ data = @@default_values[@name]
58
+ else
59
+ puts "WARNING nil value supplied for [#{@name}] - No default"
60
+ end if(data.nil?)
61
+
62
+ data = "#{@@prefixes[@name]}#{data}" if(@@prefixes[@name])
63
+
64
+ if( @belongs_to )
65
+
66
+ #puts "DEBUG : BELONGS_TO #{@belongs_to} - Lookup #{data} in DB"
67
+ insistent_belongs_to(record, data)
68
+
69
+ elsif( @assignment && @col_type )
70
+ puts "DEBUG : COl TYPE defined for #{@name} : #{@assignment} => #{data} #{@col_type.inspect}"
71
+ record.send( @assignment, @col_type.type_cast( data ) )
72
+
73
+ elsif( @assignment )
74
+ puts "DEBUG : No COL TYPE found for #{@name} : #{@assignment} => #{data}"
75
+ insistent_assignment(record, data)
76
+ end
77
+ end
78
+
79
+ # Attempt to find the associated object via id, name, title ....
80
+ def insistent_belongs_to( record, value )
81
+
82
+ @@insistent_find_by_list.each do |x|
83
+ begin
84
+ item = @belongs_to_class.send( "find_by_#{x}", value)
85
+ if(item)
86
+ record.send("#{@belongs_to}=", item)
87
+ break
88
+ end
89
+ rescue => e
90
+ puts "ERROR: #{e.inspect}"
91
+ if(x == @@insistent_method_list.last)
92
+ raise "I'm sorry I have failed to assign [#{value}] to #{@assignment}" unless value.nil?
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ def insistent_assignment( record, value )
99
+ puts "DEBUG: RECORD CLASS #{record.class}"
100
+ @@insistent_method_list ||= [:to_s, :to_i, :to_f, :to_b]
101
+ begin
102
+ record.send(@assignment, value)
103
+ rescue => e
104
+ puts e.inspect
105
+ @@insistent_method_list.each do |f|
106
+ begin
107
+
108
+ record.send(@assignment, value.send( f) )
109
+ break
110
+ rescue => e
111
+ #puts "DEBUG: insistent_assignment: #{e.inspect}"
112
+ if f == @@insistent_method_list.last
113
+ puts "I'm sorry I have failed to assign [#{value}] to #{@assignment}"
114
+ raise "I'm sorry I have failed to assign [#{value}] to #{@assignment}" unless value.nil?
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ def self.set_default_value( name, value )
122
+ @@default_values[name] = value
123
+ end
124
+
125
+ def self.default_value(name)
126
+ @@default_values[name]
127
+ end
128
+
129
+ def self.set_prefix( name, value )
130
+ @@prefixes[name] = value
131
+ end
132
+
133
+ def self.default_value(name)
134
+ @@prefixes[name]
135
+ end
136
+
137
+ def pp
138
+ "#{@name} => #{@assignment} : #{@has_many}"
139
+ end
140
+ end
@@ -1,157 +1,157 @@
1
- # Copyright:: (c) Autotelik Media Ltd 2011
2
- # Author :: Tom Statter
3
- # Date :: Aug 2010
4
- # License:: MIT
5
- #
6
- # Details:: A base class that stores details of all possible associations on AR classes and,
7
- # given user supplied class and name, attempts to find correct attribute/association.
8
- #
9
- # Derived classes define where the user supplied list of names originates from.
10
- #
11
- # Example usage, load from a spreadsheet where the column names are only
12
- # an approximation of the actual associations. Given a column heading of
13
- # 'Product Properties' on class Product, find_method_detail() would search AR model,
14
- # and return details of real has_many association 'product_properties'.
15
- #
16
- # This real association can then be used to send spreadsheet row data to the AR object.
17
- #
18
- require 'method_detail'
19
-
20
- class MethodMapper
21
-
22
- attr_accessor :header_row, :headers
23
- attr_accessor :methods
24
-
25
- @@has_many = Hash.new
26
- @@belongs_to = Hash.new
27
- @@assignments = Hash.new
28
- @@column_types = Hash.new
29
-
30
- def initialize
31
- @methods = []
32
- @headers = []
33
- end
34
-
35
- # Build complete picture of the methods whose names listed in method_list
36
- # Handles method names as defined by a user or in file headers where names may
37
- # not be exactly as required e.g handles capitalisation, white space, _ etc
38
-
39
- def find_method_details( klass, method_list )
40
- @methods = method_list.collect { |x| MethodMapper::find_method_detail( klass, x ) }
41
- end
42
-
43
- def method_names()
44
- @methods.collect( &:name )
45
- end
46
-
47
- def check_mandatory( mandatory_list )
48
- method_list = method_names()
49
-
50
- mandatory_list.each { |x| raise "Mandatory column missing - need a '#{x}' column" unless(method_list.index(x)) }
51
- end
52
-
53
- # Create picture of the operators for assignment available on an AR model,
54
- # including via associations (which provide both << and = )
55
- #
56
- def self.find_operators(klass, options = {} )
57
-
58
- if( options[:reload] || @@has_many[klass].nil? )
59
- @@has_many[klass] = klass.reflect_on_all_associations(:has_many).map { |i| i.name.to_s }
60
- klass.reflect_on_all_associations(:has_and_belongs_to_many).inject(@@has_many[klass]) { |x,i| x << i.name.to_s }
61
- end
62
-
63
- # puts "DEBUG: Has Many Associations:", @@has_many[klass].inspect
64
-
65
- if( options[:reload] || @@belongs_to[klass].nil? )
66
- @@belongs_to[klass] = klass.reflect_on_all_associations(:belongs_to).map { |i| i.name.to_s }
67
- end
68
-
69
- # puts "DEBUG: Belongs To Associations:", @@belongs_to[klass].inspect
70
-
71
- if( options[:reload] || @@assignments[klass].nil? )
72
- @@assignments[klass] = (klass.column_names + klass.instance_methods.grep(/=/).map{|i| i.gsub(/=/, '')})
73
- @@assignments[klass] = @@assignments[klass] - @@has_many[klass] if(@@has_many[klass])
74
- @@assignments[klass] = @@assignments[klass] - @@belongs_to[klass] if(@@belongs_to[klass])
75
-
76
- @@assignments[klass].uniq!
77
-
78
- @@assignments[klass].each do |assign|
79
- found = klass.columns.find{ |col| col.name == assign }
80
- @@column_types[column_key(klass, assign)] = found if found
81
- end
82
- end
83
- end
84
-
85
- # Find the proper format of name, appropriate call + column type for a given name.
86
- # e.g Given users entry in spread sheet check for pluralization, missing underscores etc
87
- #
88
- # If not nil returned method can be used directly in for example klass.new.send( call, .... )
89
- #
90
- def self.find_method_detail( klass, name )
91
- true_name, assign, belongs_to, has_many = nil, nil, nil, nil
92
-
93
- # TODO - check out regexp to do this work better plus Inflections ??
94
- [
95
- name,
96
- name.gsub(' ', '_'),
97
- name.gsub(' ', ''),
98
- name.gsub(' ', '_').downcase,
99
- name.gsub(' ', '').downcase,
100
- name.gsub(' ', '_').underscore
101
-
102
- ].each do |n|
103
- has_many = (@@has_many[klass] && @@has_many[klass].include?(n)) ? n : nil
104
- belongs_to = (@@belongs_to[klass] && @@belongs_to[klass].include?(n)) ? n : nil
105
- assign = (@@assignments[klass] && @@assignments[klass].include?(n))? n + '=' : nil
106
-
107
- if(assign || has_many || belongs_to)
108
- true_name = n
109
- break
110
- end
111
- end
112
-
113
- return MethodDetail.new(klass, true_name, assign, belongs_to, has_many, @@column_types[column_key(klass, true_name)])
114
- end
115
-
116
- def self.clear
117
- @@has_many.clear
118
- @@assignments.clear
119
- @@column_types.clear
120
- end
121
-
122
- def self.column_key(klass, column)
123
- "#{klass.name}:#{column}"
124
- end
125
-
126
- def self.has_many
127
- @@has_many
128
- end
129
- def self.assignments
130
- @@assignments
131
- end
132
- def self.column_types
133
- @@column_types
134
- end
135
-
136
- def self.has_many_for(klass)
137
- @@has_many[klass]
138
- end
139
- def self.assignments_for(klass)
140
- @@assignments[klass]
141
- end
142
-
143
- def self.column_type_for(klass, column)
144
- @@column_types[column_key(klass, column)]
145
- end
146
-
147
-
148
- def find_or_new( klass, condition_hash = {} )
149
- @records[klass] = klass.find(:all, :conditions => condition_hash)
150
- if @records[klass].any?
151
- return @records[klass].first
152
- else
153
- return klass.new
154
- end
155
- end
156
-
1
+ # Copyright:: (c) Autotelik Media Ltd 2011
2
+ # Author :: Tom Statter
3
+ # Date :: Aug 2010
4
+ # License:: MIT
5
+ #
6
+ # Details:: A base class that stores details of all possible associations on AR classes and,
7
+ # given user supplied class and name, attempts to find correct attribute/association.
8
+ #
9
+ # Derived classes define where the user supplied list of names originates from.
10
+ #
11
+ # Example usage, load from a spreadsheet where the column names are only
12
+ # an approximation of the actual associations. Given a column heading of
13
+ # 'Product Properties' on class Product, find_method_detail() would search AR model,
14
+ # and return details of real has_many association 'product_properties'.
15
+ #
16
+ # This real association can then be used to send spreadsheet row data to the AR object.
17
+ #
18
+ require 'method_detail'
19
+
20
+ class MethodMapper
21
+
22
+ attr_accessor :header_row, :headers
23
+ attr_accessor :methods
24
+
25
+ @@has_many = Hash.new
26
+ @@belongs_to = Hash.new
27
+ @@assignments = Hash.new
28
+ @@column_types = Hash.new
29
+
30
+ def initialize
31
+ @methods = []
32
+ @headers = []
33
+ end
34
+
35
+ # Build complete picture of the methods whose names listed in method_list
36
+ # Handles method names as defined by a user or in file headers where names may
37
+ # not be exactly as required e.g handles capitalisation, white space, _ etc
38
+
39
+ def find_method_details( klass, method_list )
40
+ @methods = method_list.collect { |x| MethodMapper::find_method_detail( klass, x ) }
41
+ end
42
+
43
+ def method_names()
44
+ @methods.collect( &:name )
45
+ end
46
+
47
+ def check_mandatory( mandatory_list )
48
+ method_list = method_names()
49
+
50
+ mandatory_list.each { |x| raise "Mandatory column missing - need a '#{x}' column" unless(method_list.index(x)) }
51
+ end
52
+
53
+ # Create picture of the operators for assignment available on an AR model,
54
+ # including via associations (which provide both << and = )
55
+ #
56
+ def self.find_operators(klass, options = {} )
57
+
58
+ if( options[:reload] || @@has_many[klass].nil? )
59
+ @@has_many[klass] = klass.reflect_on_all_associations(:has_many).map { |i| i.name.to_s }
60
+ klass.reflect_on_all_associations(:has_and_belongs_to_many).inject(@@has_many[klass]) { |x,i| x << i.name.to_s }
61
+ end
62
+
63
+ # puts "DEBUG: Has Many Associations:", @@has_many[klass].inspect
64
+
65
+ if( options[:reload] || @@belongs_to[klass].nil? )
66
+ @@belongs_to[klass] = klass.reflect_on_all_associations(:belongs_to).map { |i| i.name.to_s }
67
+ end
68
+
69
+ # puts "DEBUG: Belongs To Associations:", @@belongs_to[klass].inspect
70
+
71
+ if( options[:reload] || @@assignments[klass].nil? )
72
+ @@assignments[klass] = (klass.column_names + klass.instance_methods.grep(/=/).map{|i| i.gsub(/=/, '')})
73
+ @@assignments[klass] = @@assignments[klass] - @@has_many[klass] if(@@has_many[klass])
74
+ @@assignments[klass] = @@assignments[klass] - @@belongs_to[klass] if(@@belongs_to[klass])
75
+
76
+ @@assignments[klass].uniq!
77
+
78
+ @@assignments[klass].each do |assign|
79
+ found = klass.columns.find{ |col| col.name == assign }
80
+ @@column_types[column_key(klass, assign)] = found if found
81
+ end
82
+ end
83
+ end
84
+
85
+ # Find the proper format of name, appropriate call + column type for a given name.
86
+ # e.g Given users entry in spread sheet check for pluralization, missing underscores etc
87
+ #
88
+ # If not nil returned method can be used directly in for example klass.new.send( call, .... )
89
+ #
90
+ def self.find_method_detail( klass, name )
91
+ true_name, assign, belongs_to, has_many = nil, nil, nil, nil
92
+
93
+ # TODO - check out regexp to do this work better plus Inflections ??
94
+ [
95
+ name,
96
+ name.gsub(' ', '_'),
97
+ name.gsub(' ', ''),
98
+ name.gsub(' ', '_').downcase,
99
+ name.gsub(' ', '').downcase,
100
+ name.gsub(' ', '_').underscore
101
+
102
+ ].each do |n|
103
+ has_many = (@@has_many[klass] && @@has_many[klass].include?(n)) ? n : nil
104
+ belongs_to = (@@belongs_to[klass] && @@belongs_to[klass].include?(n)) ? n : nil
105
+ assign = (@@assignments[klass] && @@assignments[klass].include?(n))? n + '=' : nil
106
+
107
+ if(assign || has_many || belongs_to)
108
+ true_name = n
109
+ break
110
+ end
111
+ end
112
+
113
+ return MethodDetail.new(klass, true_name, assign, belongs_to, has_many, @@column_types[column_key(klass, true_name)])
114
+ end
115
+
116
+ def self.clear
117
+ @@has_many.clear
118
+ @@assignments.clear
119
+ @@column_types.clear
120
+ end
121
+
122
+ def self.column_key(klass, column)
123
+ "#{klass.name}:#{column}"
124
+ end
125
+
126
+ def self.has_many
127
+ @@has_many
128
+ end
129
+ def self.assignments
130
+ @@assignments
131
+ end
132
+ def self.column_types
133
+ @@column_types
134
+ end
135
+
136
+ def self.has_many_for(klass)
137
+ @@has_many[klass]
138
+ end
139
+ def self.assignments_for(klass)
140
+ @@assignments[klass]
141
+ end
142
+
143
+ def self.column_type_for(klass, column)
144
+ @@column_types[column_key(klass, column)]
145
+ end
146
+
147
+
148
+ def find_or_new( klass, condition_hash = {} )
149
+ @records[klass] = klass.find(:all, :conditions => condition_hash)
150
+ if @records[klass].any?
151
+ return @records[klass].first
152
+ else
153
+ return klass.new
154
+ end
155
+ end
156
+
157
157
  end
@@ -1,28 +1,28 @@
1
- # Copyright:: (c) Autotelik Media Ltd 2011
2
- # Author :: Tom Statter
3
- # Date :: Jan 2011
4
- # License:: MIT
5
- #
6
- # Details:: Extract the headings from a user supplied CSV file, and map heading names
7
- # to the attributes and/or assocaiitons of an AR Model defined by supplied klass.
8
- #
9
- require 'method_mapper'
10
-
11
- class MethodMapperCsv < MethodMapper
12
-
13
- # Read the headers from CSV file and map to ActiveRecord members/associations
14
-
15
- def initialize( file_name, klass, sheet_number = 0 )
16
- super
17
-
18
- File.open(file_name) do
19
- @headers = @header_row.split(/,/)
20
- end
21
-
22
- # Gather list of all possible 'setter' methods on AR class (instance variables and associations)
23
- self.find_operators( klass )
24
-
25
- # Convert the list of headers into suitable calls on the Active Record class
26
- find_method_details( klass, @headers )
27
- end
1
+ # Copyright:: (c) Autotelik Media Ltd 2011
2
+ # Author :: Tom Statter
3
+ # Date :: Jan 2011
4
+ # License:: MIT
5
+ #
6
+ # Details:: Extract the headings from a user supplied CSV file, and map heading names
7
+ # to the attributes and/or assocaiitons of an AR Model defined by supplied klass.
8
+ #
9
+ require 'method_mapper'
10
+
11
+ class MethodMapperCsv < MethodMapper
12
+
13
+ # Read the headers from CSV file and map to ActiveRecord members/associations
14
+
15
+ def initialize( file_name, klass, sheet_number = 0 )
16
+ super
17
+
18
+ File.open(file_name) do
19
+ @headers = @header_row.split(/,/)
20
+ end
21
+
22
+ # Gather list of all possible 'setter' methods on AR class (instance variables and associations)
23
+ self.find_operators( klass )
24
+
25
+ # Convert the list of headers into suitable calls on the Active Record class
26
+ find_method_details( klass, @headers )
27
+ end
28
28
  end