garden 0.0.4.pre → 0.0.5.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/garden/helpers/real_instance.rb +30 -0
- data/lib/garden/helpers.rb +7 -0
- data/lib/garden/instance.rb +157 -0
- data/lib/garden/mediators.rb +2 -108
- data/lib/garden/spreadsheets.rb +42 -36
- data/lib/garden/version.rb +1 -1
- data/lib/garden.rb +9 -6
- metadata +6 -3
@@ -0,0 +1,30 @@
|
|
1
|
+
module Garden
|
2
|
+
module Helpers
|
3
|
+
module RealInstance
|
4
|
+
def get_real_instance(table, id)
|
5
|
+
model_name = table.is_a?(ActiveRecord::Reflection::AssociationReflection) ? table.class_name : table.to_s.classify
|
6
|
+
|
7
|
+
begin
|
8
|
+
clazz = model_name.constantize
|
9
|
+
raise "Class #{clazz.to_s} is not an ActiveRecord subclass." unless clazz.new.is_a?(ActiveRecord::Base)
|
10
|
+
instance = clazz.find(id.to_s)
|
11
|
+
|
12
|
+
# puts "!! Created clazz #{clazz.to_s} from model_name. No problem. #{instance.class.to_s} #{instance.to_param}"
|
13
|
+
|
14
|
+
return instance
|
15
|
+
rescue ActiveRecord::RecordNotFound => e
|
16
|
+
|
17
|
+
instance = clazz.find_by_name(id.to_s) if instance.nil? && clazz.respond_to?(:find_by_name)
|
18
|
+
# puts "++Find #{clazz.to_s} by title: #{id}" if instance.nil? && clazz.respond_to?(:find_by_title)
|
19
|
+
instance = clazz.find_by_title(id.to_s) if instance.nil? && clazz.respond_to?(:find_by_title)
|
20
|
+
# puts "++#{instance}" if instance
|
21
|
+
return instance
|
22
|
+
rescue Exception => e
|
23
|
+
puts "Could not find #{id} from table #{model_name}: #{e.message}"
|
24
|
+
return nil
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
|
2
|
+
module Garden
|
3
|
+
class Instance
|
4
|
+
|
5
|
+
module Reflection
|
6
|
+
# If an association method is passed in (f.input :author) try to find the
|
7
|
+
# reflection object.
|
8
|
+
def reflection_for(method) #:nodoc:
|
9
|
+
if @object.class.respond_to?(:reflect_on_association)
|
10
|
+
@object.class.reflect_on_association(method)
|
11
|
+
elsif @object.class.respond_to?(:associations) # MongoMapper uses the 'associations(method)' instead
|
12
|
+
@object.class.associations(method)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def association_macro_for_method(method) #:nodoc:
|
17
|
+
reflection = reflection_for(method)
|
18
|
+
reflection.macro if reflection
|
19
|
+
end
|
20
|
+
|
21
|
+
def association_primary_key_for_method(method) #:nodoc:
|
22
|
+
reflection = reflection_for(method)
|
23
|
+
if reflection
|
24
|
+
case association_macro_for_method(method)
|
25
|
+
when :has_and_belongs_to_many, :has_many, :references_and_referenced_in_many, :references_many
|
26
|
+
:"#{method.to_s.singularize}_ids"
|
27
|
+
else
|
28
|
+
return reflection.foreign_key.to_sym if reflection.respond_to?(:foreign_key)
|
29
|
+
return reflection.options[:foreign_key].to_sym unless reflection.options[:foreign_key].blank?
|
30
|
+
:"#{method}_id"
|
31
|
+
end
|
32
|
+
else
|
33
|
+
method.to_sym
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
module Columns
|
38
|
+
# Get a column object for a specified attribute method - if possible.
|
39
|
+
def column_for(method) #:nodoc:
|
40
|
+
@object.column_for_attribute(method) if @object.respond_to?(:column_for_attribute)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
include Reflection
|
45
|
+
include Columns
|
46
|
+
|
47
|
+
def initialize(clazz, attributes=nil)
|
48
|
+
@object = clazz.new
|
49
|
+
assign_attributes attributes if attributes
|
50
|
+
end
|
51
|
+
|
52
|
+
def assign_attributes(attributes)
|
53
|
+
|
54
|
+
attributes.each do |key, value|
|
55
|
+
map_attribute key, value
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
# parse_row_relationships @object, attributes#, relationships
|
61
|
+
|
62
|
+
# puts "A: #{attributes.keys}"
|
63
|
+
|
64
|
+
# rejected = {}
|
65
|
+
# attributes.each_key do |key|
|
66
|
+
# rejected[key] = attributes.delete(key) if !@object.attributes.include?(key.to_s)# && !relationships.include?(key.to_s)
|
67
|
+
# end
|
68
|
+
|
69
|
+
|
70
|
+
# attributes.delete_if do |key, value| !@object.attributes.include?(key.to_s) end
|
71
|
+
|
72
|
+
# see https://github.com/justinfrench/formtastic/blob/master/lib/formtastic/helpers/input_helper.rb
|
73
|
+
|
74
|
+
# @object.attributes = attributes
|
75
|
+
|
76
|
+
# @object.id = rejected[:id] if rejected.key?(:id)
|
77
|
+
|
78
|
+
|
79
|
+
if @object.valid?
|
80
|
+
@object.save!
|
81
|
+
puts ".Saved instance: #{@clazz} #{@object.to_param}"
|
82
|
+
else
|
83
|
+
puts "Invalid instance."
|
84
|
+
puts "#{@name}:"
|
85
|
+
# puts " - Valid attributes: #{attributes.keys}"
|
86
|
+
# puts " - Excel sheet keys: #{all_keys}"
|
87
|
+
# puts " - Invalid attributes: #{rejected.keys}"
|
88
|
+
# puts " - Association attributes: #{relationships}"
|
89
|
+
puts "Attributes from excel: #{attributes}"
|
90
|
+
# @object.errors.each do |error|
|
91
|
+
# puts "Error => #{error}: #{@object.errors.get error}"
|
92
|
+
# end
|
93
|
+
puts @object.errors.to_a
|
94
|
+
puts "."
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def map_attribute(key, value)
|
99
|
+
|
100
|
+
if reflection = reflection_for(key)
|
101
|
+
# There is an assocation for this column.
|
102
|
+
case reflection.macro
|
103
|
+
when :has_many
|
104
|
+
parse_has_many(reflection, value)
|
105
|
+
when :belongs_to
|
106
|
+
parse_belongs_to(reflection, value)
|
107
|
+
end
|
108
|
+
|
109
|
+
return
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
if column = column_for(key)
|
114
|
+
|
115
|
+
case column.type
|
116
|
+
|
117
|
+
# Special cases where the column type doesn't map to an input method.
|
118
|
+
when :string
|
119
|
+
|
120
|
+
when :integer
|
121
|
+
|
122
|
+
when :float, :decimal
|
123
|
+
|
124
|
+
when :timestamp
|
125
|
+
# todo: parse a timestamp
|
126
|
+
when :boolean
|
127
|
+
value = ((value =~ /y|yes|true|t|1/i) || -1) >= 0
|
128
|
+
end
|
129
|
+
|
130
|
+
@object.send "#{key}=", value
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
def parse_has_many r, value
|
136
|
+
# puts " // Parsing #{r.name}, #{value}"
|
137
|
+
ids = value.split(/\s*,\s*/)
|
138
|
+
ids.each do |id|
|
139
|
+
related_instance = get_real_instance r.class_name, id
|
140
|
+
# puts ">> Creating a has-many relationship. #{id}, #{related_instance}"
|
141
|
+
unless related_instance.nil?
|
142
|
+
@object.send(r.name.to_sym) << related_instance
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def parse_belongs_to r, value
|
148
|
+
ri = get_real_instance(r, value)
|
149
|
+
@object.attributes = { r.name.to_sym => ri }
|
150
|
+
# puts "Parsing Belongs_To. #{@object.class} #{@object.to_param} --- #{r.name.to_sym} --- #{ri.class} #{ri.to_param}"
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
Instance.send :include, Helpers::RealInstance
|
156
|
+
|
157
|
+
end
|
data/lib/garden/mediators.rb
CHANGED
@@ -5,33 +5,6 @@ module Garden
|
|
5
5
|
def self.parse_table_name namish
|
6
6
|
namish.parameterize.underscore
|
7
7
|
end
|
8
|
-
def self.get_instance table, id
|
9
|
-
|
10
|
-
model_name = table.is_a?(ActiveRecord::Reflection::AssociationReflection) ? table.class_name : table.to_s.classify
|
11
|
-
|
12
|
-
# puts "Find #{id} from #{table_name}"
|
13
|
-
# puts id.class.to_s
|
14
|
-
|
15
|
-
begin
|
16
|
-
clazz = model_name.constantize
|
17
|
-
raise "Class #{clazz.to_s} is not an ActiveRecord subclass." unless clazz.new.is_a?(ActiveRecord::Base)
|
18
|
-
instance = clazz.find(id.to_s)
|
19
|
-
|
20
|
-
# puts "!! Created clazz #{clazz.to_s} from model_name. No problem. #{instance.class.to_s} #{instance.to_param}"
|
21
|
-
|
22
|
-
return instance
|
23
|
-
rescue ActiveRecord::RecordNotFound => e
|
24
|
-
|
25
|
-
instance = clazz.find_by_name(id.to_s) if instance.nil? && clazz.respond_to?(:find_by_name)
|
26
|
-
# puts "++Find #{clazz.to_s} by title: #{id}" if instance.nil? && clazz.respond_to?(:find_by_title)
|
27
|
-
instance = clazz.find_by_title(id.to_s) if instance.nil? && clazz.respond_to?(:find_by_title)
|
28
|
-
# puts "++#{instance}" if instance
|
29
|
-
return instance
|
30
|
-
rescue Exception => e
|
31
|
-
puts "Could not find #{id} from table #{model_name}: #{e.message}"
|
32
|
-
return nil
|
33
|
-
end
|
34
|
-
end
|
35
8
|
|
36
9
|
def initialize namish
|
37
10
|
|
@@ -67,88 +40,9 @@ module Garden
|
|
67
40
|
# end
|
68
41
|
#
|
69
42
|
def create_instance attributes
|
70
|
-
|
71
|
-
|
72
|
-
all_keys = attributes.keys
|
73
|
-
|
74
|
-
instance = @clazz.new
|
75
|
-
parse_row_relationships instance, attributes#, relationships
|
76
|
-
|
77
|
-
# puts "A: #{attributes.keys}"
|
78
|
-
|
79
|
-
# rejected = {}
|
80
|
-
# attributes.each_key do |key|
|
81
|
-
# rejected[key] = attributes.delete(key) if !instance.attributes.include?(key.to_s)# && !relationships.include?(key.to_s)
|
82
|
-
# end
|
83
|
-
|
84
|
-
|
85
|
-
attributes.delete_if do |key, value| !instance.attributes.include?(key.to_s) end
|
86
|
-
instance.attributes = attributes
|
87
|
-
|
88
|
-
# instance.id = rejected[:id] if rejected.key?(:id)
|
89
|
-
|
90
|
-
# puts "Valid? #{instance.valid?}"
|
91
|
-
# puts instance.errors.to_s
|
92
|
-
|
93
|
-
valid = instance.valid?
|
94
|
-
|
95
|
-
if instance.valid?
|
96
|
-
instance.save!
|
97
|
-
puts ".Saved instance: #{@clazz} #{instance.to_param}"
|
98
|
-
else
|
99
|
-
puts "Invalid instance."
|
100
|
-
puts "#{@name}:"
|
101
|
-
puts " - Valid attributes: #{attributes.keys}"
|
102
|
-
puts " - Excel sheet keys: #{all_keys}"
|
103
|
-
# puts " - Invalid attributes: #{rejected.keys}"
|
104
|
-
# puts " - Association attributes: #{relationships}"
|
105
|
-
instance.errors.each do |error|
|
106
|
-
puts error
|
107
|
-
end
|
108
|
-
end
|
43
|
+
Instance.new @clazz, attributes
|
109
44
|
end
|
110
|
-
|
111
|
-
def parse_row_relationships instance, hash#, relationships
|
112
|
-
@clazz.reflections.each_value do |r|
|
113
|
-
next unless hash.has_key?(r.name)
|
114
|
-
# Remove the value from the hash.
|
115
|
-
value = hash.delete(r.name.to_sym)
|
116
|
-
case r.macro
|
117
|
-
when :has_many
|
118
|
-
parse_has_many(instance, r, value)
|
119
|
-
when :belongs_to
|
120
|
-
parse_belongs_to(instance, r, value)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# relationships.each do |r|
|
125
|
-
# # puts "Parsing row relationship: #{hash[r.to_sym]}"
|
126
|
-
# instance = get_instance r, hash[r.to_sym]
|
127
|
-
# hash[r.to_sym] = instance
|
128
|
-
# end
|
129
|
-
# hash
|
130
|
-
end
|
131
|
-
|
132
|
-
|
133
|
-
def parse_has_many instance, r, value
|
134
|
-
# puts " // Parsing #{r.name}, #{value}"
|
135
|
-
ids = value.split(/\s*,\s*/)
|
136
|
-
ids.each do |id|
|
137
|
-
related_instance = Table.get_instance r.class_name, id
|
138
|
-
# puts ">> Creating a has-many relationship. #{id}, #{related_instance}"
|
139
|
-
unless related_instance.nil?
|
140
|
-
instance.send(r.name.to_sym) << related_instance
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def parse_belongs_to instance, r, value
|
146
|
-
ri = Table.get_instance(r, value)
|
147
|
-
instance.attributes = { r.name.to_sym => ri }
|
148
|
-
|
149
|
-
# puts "Parsing Belongs_To. #{instance.class} #{instance.to_param} --- #{r.name.to_sym} --- #{ri.class} #{ri.to_param}"
|
150
|
-
end
|
151
|
-
|
45
|
+
|
152
46
|
end
|
153
47
|
end
|
154
48
|
end
|
data/lib/garden/spreadsheets.rb
CHANGED
@@ -1,52 +1,58 @@
|
|
1
1
|
require 'spreadsheet'
|
2
2
|
|
3
3
|
module Garden
|
4
|
-
|
4
|
+
module Spreadsheets
|
5
|
+
class Excel
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
def initialize filepath, options={}
|
8
|
+
options ||= {}
|
9
|
+
|
10
|
+
@options = options.reverse_merge! :some_option => "nevermind"
|
11
|
+
|
12
|
+
open filepath
|
13
|
+
end
|
9
14
|
|
10
|
-
|
11
|
-
|
15
|
+
def open filepath
|
16
|
+
puts "Planting spreadsheet: #{filepath}"
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
@ss = Spreadsheet.open filepath
|
19
|
+
worksheet_names = @options[:only] || @options[:worksheet] || @ss.worksheets.collect { |table| table.name }
|
20
|
+
worksheet_names = [worksheet_names] unless worksheet_names.is_a?(Enumerable)
|
21
|
+
|
22
|
+
# Import the worksheets
|
23
|
+
worksheet_names.each do |name|
|
24
|
+
puts "Parsing table #{name}"
|
25
|
+
parse_table @ss.worksheets.find { |table| table.name == name.to_s }
|
26
|
+
end
|
18
27
|
|
19
|
-
|
28
|
+
end
|
20
29
|
|
21
|
-
|
22
|
-
|
30
|
+
def parse_table table
|
31
|
+
# The table object passed in is a Spreadsheet::Worksheet instance.
|
23
32
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
33
|
+
table_mediator = Mediators::Table.new table.name
|
34
|
+
if !table_mediator.valid?
|
35
|
+
return
|
36
|
+
end
|
28
37
|
|
29
|
-
|
30
|
-
|
38
|
+
# Get the headers. These values will be the attribute names
|
39
|
+
headers = table_mediator.parse_headers table.first.to_a
|
31
40
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
table_mediator.create_instance parse_worksheet_row(headers, row)
|
41
|
+
# Now loop the table rows, inserting records.
|
42
|
+
table.each do |row|
|
43
|
+
next if row.idx == 0
|
44
|
+
table_mediator.create_instance parse_worksheet_row(headers, row)
|
45
|
+
end
|
38
46
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
47
|
+
|
48
|
+
def parse_worksheet_row keys, values
|
49
|
+
h = {}
|
50
|
+
keys.each_index do |index|
|
51
|
+
key = keys[index].to_sym
|
52
|
+
h[key] = values[index]
|
53
|
+
end
|
54
|
+
h
|
46
55
|
end
|
47
|
-
h
|
48
56
|
end
|
49
|
-
|
50
|
-
|
51
57
|
end
|
52
58
|
end
|
data/lib/garden/version.rb
CHANGED
data/lib/garden.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require "garden/version"
|
2
2
|
|
3
3
|
module Garden
|
4
|
-
|
5
|
-
|
6
|
-
autoload :
|
7
|
-
|
4
|
+
extend ActiveSupport::Autoload
|
5
|
+
|
6
|
+
autoload :Spreadsheets
|
7
|
+
autoload :Mediators
|
8
|
+
autoload :Helpers
|
9
|
+
autoload :Instance
|
10
|
+
|
8
11
|
# def self.plant
|
9
12
|
# # todo
|
10
13
|
# end
|
@@ -18,9 +21,9 @@ module Garden
|
|
18
21
|
# # todo
|
19
22
|
# end
|
20
23
|
|
21
|
-
def self.excel file_name_or_path
|
24
|
+
def self.excel file_name_or_path, options=nil
|
22
25
|
filepath = resolve_file_path(file_name_or_path)
|
23
|
-
Excel.new filepath
|
26
|
+
Spreadsheets::Excel.new filepath, options
|
24
27
|
end
|
25
28
|
|
26
29
|
def self.resolve_file_path name_or_path
|
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.5.pre
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2011-09-16 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: spreadsheet
|
16
|
-
requirement: &
|
16
|
+
requirement: &70343008328480 !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: *70343008328480
|
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:
|
@@ -36,6 +36,9 @@ files:
|
|
36
36
|
- Rakefile
|
37
37
|
- garden.gemspec
|
38
38
|
- lib/garden.rb
|
39
|
+
- lib/garden/helpers.rb
|
40
|
+
- lib/garden/helpers/real_instance.rb
|
41
|
+
- lib/garden/instance.rb
|
39
42
|
- lib/garden/mediators.rb
|
40
43
|
- lib/garden/spreadsheets.rb
|
41
44
|
- lib/garden/version.rb
|