garden 0.0.4.pre → 0.0.5.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/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
|