garden 0.0.15.pre → 0.0.16.pre
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 +32 -0
- data/lib/garden.rb +1 -0
- data/lib/garden/instance.rb +50 -8
- data/lib/garden/mediators.rb +13 -50
- data/lib/garden/models.rb +77 -0
- data/lib/garden/spreadsheets.rb +11 -5
- data/lib/garden/version.rb +1 -1
- metadata +6 -5
- data/README.markdown +0 -5
data/README.textile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
A utility for using different seed formats in your ActiveRecord database.
|
2
|
+
|
3
|
+
In process. Currently supports:
|
4
|
+
|
5
|
+
Excel spreadsheet format:
|
6
|
+
|
7
|
+
Garden.excel 'spreadsheetname'
|
8
|
+
|
9
|
+
CSV spreadsheet format:
|
10
|
+
|
11
|
+
Garden.csv 'spreadsheetname'
|
12
|
+
|
13
|
+
Common options:
|
14
|
+
|
15
|
+
:reference >> The column name to use as a reference for updating values.
|
16
|
+
|
17
|
+
:validate >> [Boolean][default=true] >> Whether to perform validations on ActiveRecord::Base instances
|
18
|
+
|
19
|
+
:only >> (Excel only) whitelist the worksheet names to seed
|
20
|
+
:worksheet >> (Excel only) whitelist the single worksheet name to seed
|
21
|
+
|
22
|
+
:table >> (CSV only) the table name to seed into (defaults to an interpretation based on the csv filename)
|
23
|
+
|
24
|
+
Callbacks:
|
25
|
+
Callbacks allow for methods and actions to be injected in the process of the seeding of data. The most common callbacks are those
|
26
|
+
that will be called on each instance that is created by the seed process.
|
27
|
+
|
28
|
+
:before_validation
|
29
|
+
If option is a method or Proc instance, it will be called with the record as the first argument.
|
30
|
+
If option is a symbol, Garden expects it refers to the name of a method for that instance and will call it on the record.
|
31
|
+
|
32
|
+
|
data/lib/garden.rb
CHANGED
data/lib/garden/instance.rb
CHANGED
@@ -47,8 +47,9 @@ module Garden
|
|
47
47
|
include Columns
|
48
48
|
|
49
49
|
def initialize(clazz, attributes=nil, options={})
|
50
|
-
@options = options.dup
|
51
|
-
|
50
|
+
@options = options.dup.symbolize_keys
|
51
|
+
# initialize_callbacks
|
52
|
+
|
52
53
|
if @options.has_key? :reference
|
53
54
|
@reference_column = @options.delete(:reference).to_sym
|
54
55
|
@reference = attributes.delete @reference_column
|
@@ -65,6 +66,17 @@ module Garden
|
|
65
66
|
assign_attributes attributes if attributes
|
66
67
|
end
|
67
68
|
|
69
|
+
# def initialize_callbacks
|
70
|
+
# for name in active_record_callbacks do
|
71
|
+
#
|
72
|
+
#
|
73
|
+
#
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# @callbacks = {}
|
77
|
+
# @callbacks[:before_validation] = @options.delete(:before_validation) if @options.has_key?(:before_validation)
|
78
|
+
# end
|
79
|
+
|
68
80
|
def assign_attributes(attributes)
|
69
81
|
|
70
82
|
attributes.each do |key, value|
|
@@ -72,16 +84,16 @@ module Garden
|
|
72
84
|
map_attribute key, value
|
73
85
|
end
|
74
86
|
|
75
|
-
|
76
|
-
|
77
|
-
|
87
|
+
# execute_callback(:before_validation)
|
88
|
+
|
89
|
+
if @object.save(:validate => @options[:validate])
|
78
90
|
if @reference.nil?
|
79
91
|
puts ". Saved new instance: #{@clazz} #{@object.to_param}"
|
80
92
|
else
|
81
93
|
puts ". Saved existing instance: #{@clazz} #{@object.to_param}"
|
82
94
|
end
|
83
95
|
else
|
84
|
-
puts "!
|
96
|
+
puts "! Instance was not saved: #{@object.to_param}"
|
85
97
|
# puts "#{@name}:"
|
86
98
|
# puts " - Valid attributes: #{attributes.keys}"
|
87
99
|
# puts " - Excel sheet keys: #{all_keys}"
|
@@ -91,7 +103,9 @@ module Garden
|
|
91
103
|
# @object.errors.each do |error|
|
92
104
|
# puts "Error => #{error}: #{@object.errors.get error}"
|
93
105
|
# end
|
94
|
-
|
106
|
+
if @object.errors.any?
|
107
|
+
puts @object.errors.to_a
|
108
|
+
end
|
95
109
|
puts "."
|
96
110
|
end
|
97
111
|
|
@@ -152,7 +166,7 @@ module Garden
|
|
152
166
|
# build the association if it hasn't already been built.
|
153
167
|
@object.send("build_#{assoc}".to_sym)
|
154
168
|
end
|
155
|
-
eval "@object.#{key} = '#{value.gsub(/[']/, '\\\\\'')}'"
|
169
|
+
eval "@object.#{key} = '#{value.to_s.gsub(/[']/, '\\\\\'')}'"
|
156
170
|
return
|
157
171
|
end
|
158
172
|
|
@@ -195,6 +209,34 @@ module Garden
|
|
195
209
|
|
196
210
|
end
|
197
211
|
|
212
|
+
# def execute_callback name
|
213
|
+
# name = name.to_sym
|
214
|
+
# callback = @callbacks[name]
|
215
|
+
#
|
216
|
+
# if callback
|
217
|
+
#
|
218
|
+
# if active_record_callbacks.include?(name)
|
219
|
+
# # Execute a callback by applying it to the ActiveRecord model.
|
220
|
+
#
|
221
|
+
# else
|
222
|
+
#
|
223
|
+
# end
|
224
|
+
#
|
225
|
+
# # puts "Executing callback: #{name}, #{callback}, #{callback.class}"
|
226
|
+
# case callback
|
227
|
+
# when Proc, Method then callback.call(@object)
|
228
|
+
# when Symbol, String then record.send(callback.to_sym)
|
229
|
+
# end
|
230
|
+
# end
|
231
|
+
# end
|
232
|
+
#
|
233
|
+
# private
|
234
|
+
|
235
|
+
# def _execute_active_record_callback name, callback
|
236
|
+
#
|
237
|
+
# end
|
238
|
+
|
239
|
+
|
198
240
|
end
|
199
241
|
|
200
242
|
Instance.send :include, Helpers::RealInstance
|
data/lib/garden/mediators.rb
CHANGED
@@ -2,72 +2,35 @@ module Garden
|
|
2
2
|
module Mediators
|
3
3
|
class Table
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
# end
|
8
|
-
|
9
|
-
def self.find_model_class namish
|
10
|
-
clazz = nil
|
11
|
-
namish = namish.singularize
|
5
|
+
def initialize namish, options={}
|
6
|
+
@instance_options = options.reverse_merge!({:validate => true})
|
12
7
|
|
13
|
-
|
14
|
-
# try the format as it should be. Camelcase, and with :: or / for modules
|
15
|
-
# Module::Classname
|
16
|
-
clazz = namish.underscore.classify.constantize
|
17
|
-
rescue
|
18
|
-
begin
|
19
|
-
# try the format "Class Name" by turning spaced words into camelcase
|
20
|
-
clazz = namish.parameterize.underscore.classify.constantize
|
21
|
-
rescue
|
22
|
-
begin
|
23
|
-
# try the format "Class Name" by turning spaced words into module separators
|
24
|
-
clazz = namish.gsub(/ /, "/").underscore.classify.constantize
|
25
|
-
rescue
|
26
|
-
puts "Nope"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
clazz
|
31
|
-
end
|
32
|
-
|
33
|
-
def initialize namish
|
34
|
-
@instance_options ||= {}
|
8
|
+
# puts "Instance options: #{@instance_options}"
|
35
9
|
|
36
|
-
@clazz =
|
10
|
+
@clazz = Models.find namish, @instance_options
|
37
11
|
|
38
12
|
if @clazz.nil? || !@clazz.new.is_a?(ActiveRecord::Base)
|
39
13
|
puts "!! Class '#{namish}' could not be parsed to an ActiveRecord subclass."
|
40
14
|
end
|
41
15
|
|
42
|
-
# Get the ActiveRecord model from the tablename.
|
43
|
-
# begin
|
44
|
-
# @clazz = @name.classify.constantize
|
45
|
-
# raise "Class #{@clazz.to_s} is not an ActiveRecord subclass." unless @clazz.new.is_a?(ActiveRecord::Base)
|
46
|
-
# rescue Exception => e
|
47
|
-
# puts " ** Could not derive ActiveRecord model from the provided name: #{namish}. Exception: #{e.message}"
|
48
|
-
# end
|
49
|
-
|
50
|
-
# @instance = @clazz.new
|
51
|
-
|
52
16
|
end
|
53
17
|
|
54
18
|
def valid?
|
55
19
|
@clazz != nil
|
56
20
|
end
|
57
|
-
|
58
|
-
# def parse_headers array
|
59
|
-
# # @headers = array.map { |header| header.to_s.parameterize.underscore }
|
60
|
-
# @headers = array.map { |header| header.to_s.strip.gsub(/ /, '-').underscore }
|
61
|
-
# end
|
62
21
|
|
63
22
|
def reference_by col_name
|
64
23
|
@instance_options[:reference] = col_name
|
65
24
|
end
|
66
25
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
26
|
+
def validate=(val)
|
27
|
+
@instance_options[:validate] = val
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate
|
31
|
+
@instance_options[:validate]
|
32
|
+
end
|
33
|
+
|
71
34
|
def row attributes
|
72
35
|
Instance.new @clazz, attributes, @instance_options.dup
|
73
36
|
end
|
@@ -79,7 +42,7 @@ module Garden
|
|
79
42
|
false
|
80
43
|
end
|
81
44
|
end
|
82
|
-
|
45
|
+
|
83
46
|
end
|
84
47
|
end
|
85
48
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Garden
|
2
|
+
class Models
|
3
|
+
|
4
|
+
CALLBACKS = ActiveRecord::Callbacks::CALLBACKS
|
5
|
+
|
6
|
+
|
7
|
+
def self.find namish, options={}
|
8
|
+
|
9
|
+
# We return the found class if we've already found it.
|
10
|
+
@@found ||= {}
|
11
|
+
return @@found[namish.to_s] if @@found.has_key?(namish.to_s)
|
12
|
+
|
13
|
+
clazz = nil
|
14
|
+
namish = namish.singularize
|
15
|
+
|
16
|
+
begin
|
17
|
+
# try the format as it should be. Camelcase, and with :: or / for modules
|
18
|
+
# Module::Classname
|
19
|
+
clazz = namish.underscore.classify.constantize
|
20
|
+
rescue
|
21
|
+
begin
|
22
|
+
# try the format "Class Name" by turning spaced words into camelcase
|
23
|
+
clazz = namish.parameterize.underscore.classify.constantize
|
24
|
+
rescue
|
25
|
+
begin
|
26
|
+
# try the format "Class Name" by turning spaced words into module separators
|
27
|
+
clazz = namish.gsub(/ /, "/").underscore.classify.constantize
|
28
|
+
rescue
|
29
|
+
puts "Nope"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if clazz
|
35
|
+
apply_callbacks clazz, options
|
36
|
+
@@found[namish.to_s] = clazz
|
37
|
+
end
|
38
|
+
clazz
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.apply_callbacks clazz, callbacks
|
43
|
+
@@created_callbacks ||= []
|
44
|
+
|
45
|
+
for name in CALLBACKS do
|
46
|
+
if callbacks.has_key?(name)
|
47
|
+
callback = callbacks[name]
|
48
|
+
|
49
|
+
# Will add a callback to the ActiveRecord model
|
50
|
+
clazz.send name, Proc.new{ |record| Garden::Models.execute_callback(record, callback) }
|
51
|
+
|
52
|
+
# Retain a reference to the created callback so we can remove it later
|
53
|
+
key = name.to_s.gsub(/^(before|after|around)_/, '')
|
54
|
+
list_name = "_#{key}_callbacks"
|
55
|
+
callback_name = clazz.send(list_name).last.filter
|
56
|
+
|
57
|
+
@@created_callbacks << { :class => clazz, :list => list_name, :callback => callback_name }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.execute_callback record, callback
|
64
|
+
# puts "Executing callback on #{record.inspect}, #{callback}"
|
65
|
+
|
66
|
+
case callback
|
67
|
+
when Proc then callback.call(record)
|
68
|
+
when Symbol, String then record.send(callback.to_sym)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
data/lib/garden/spreadsheets.rb
CHANGED
@@ -7,7 +7,8 @@ module Garden
|
|
7
7
|
class AbstractSpreadsheet
|
8
8
|
def initialize filepath, options={}
|
9
9
|
options ||= {}
|
10
|
-
@options = options.reverse_merge!
|
10
|
+
# @options = options.reverse_merge! {}
|
11
|
+
@options = options
|
11
12
|
open filepath
|
12
13
|
end
|
13
14
|
|
@@ -15,7 +16,12 @@ module Garden
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def build_mediator name
|
18
|
-
|
19
|
+
validation = @options[:validate]
|
20
|
+
validation = true if validation.nil?
|
21
|
+
|
22
|
+
@options[:validate] = true if @options[:validate].nil?
|
23
|
+
|
24
|
+
@mediator = Mediators::Table.new name, @options#:validate => validation
|
19
25
|
raise "Invalid mediator for table #{name}" unless @mediator.valid?
|
20
26
|
@mediator.reference_by(@options[:reference]) if @options.has_key?(:reference)
|
21
27
|
@mediator
|
@@ -33,7 +39,7 @@ module Garden
|
|
33
39
|
|
34
40
|
excel_spreadsheet = ::Spreadsheet.open filepath
|
35
41
|
|
36
|
-
worksheet_names = @options
|
42
|
+
worksheet_names = @options.delete(:only) || @options.delete(:worksheet) || excel_spreadsheet.worksheets.collect { |table| table.name }
|
37
43
|
worksheet_names = [worksheet_names] unless worksheet_names.is_a?(Enumerable)
|
38
44
|
|
39
45
|
# Import the worksheets
|
@@ -50,12 +56,12 @@ module Garden
|
|
50
56
|
# Expects the first row to be the headers.
|
51
57
|
headers = rows.shift.map { |header| header.to_s.strip.gsub(/ /, '-').underscore }
|
52
58
|
rows.each do |row|
|
53
|
-
attributes =
|
59
|
+
attributes = parse_worksheet_attributes(headers, row)
|
54
60
|
@mediator.row attributes
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
58
|
-
def
|
64
|
+
def parse_worksheet_attributes keys, values
|
59
65
|
h = {}
|
60
66
|
keys.each_index do |index|
|
61
67
|
key = keys[index].to_sym
|
data/lib/garden/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: garden
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.16.pre
|
5
5
|
prerelease: 7
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-12-16 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: spreadsheet
|
16
|
-
requirement: &
|
16
|
+
requirement: &70188181388160 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70188181388160
|
25
25
|
description: ! 'Allows you to organize your seeds in different formats. Typical seeds.rb,
|
26
26
|
yaml fixtures, and a variety of spreadsheet formats. '
|
27
27
|
email:
|
@@ -32,7 +32,7 @@ extra_rdoc_files: []
|
|
32
32
|
files:
|
33
33
|
- .gitignore
|
34
34
|
- Gemfile
|
35
|
-
- README.
|
35
|
+
- README.textile
|
36
36
|
- Rakefile
|
37
37
|
- garden.gemspec
|
38
38
|
- lib/garden.rb
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- lib/garden/helpers/real_instance.rb
|
41
41
|
- lib/garden/instance.rb
|
42
42
|
- lib/garden/mediators.rb
|
43
|
+
- lib/garden/models.rb
|
43
44
|
- lib/garden/spreadsheets.rb
|
44
45
|
- lib/garden/version.rb
|
45
46
|
homepage: ''
|