datashift 0.10.2 → 0.11.0

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.2
1
+ 0.11.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "datashift"
8
- s.version = "0.10.2"
8
+ s.version = "0.11.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Thomas Statter"]
12
- s.date = "2012-10-21"
12
+ s.date = "2012-10-23"
13
13
  s.description = "Comprehensive tools to import/export between Excel/CSV and ActiveRecord databases, Rails apps, and any Ruby project."
14
14
  s.email = "rubygems@autotelik.co.uk"
15
15
  s.extra_rdoc_files = [
@@ -12,13 +12,11 @@ module DataShift
12
12
  class MethodDictionary
13
13
 
14
14
  include DataShift::Logging
15
-
16
- def initialize
17
- end
18
-
19
- # Has the dictionary been populated for klass
15
+
16
+ # Return true if dictionary has been populated for klass
20
17
  def self.for?(klass)
21
- return !(has_many[klass] || belongs_to[klass] || has_one[klass] || assignments[klass]).nil?
18
+ any = has_many[klass] || belongs_to[klass] || has_one[klass] || assignments[klass]
19
+ return any != nil
22
20
  end
23
21
 
24
22
  # Create simple picture of all the operator names for assignment available on an AR model,
@@ -84,8 +84,7 @@ module DataShift
84
84
  DataShift::MethodDictionary.build_method_details(klass)
85
85
  end
86
86
 
87
- forced = [*options[:force_inclusion]].compact
88
- forced.collect! { |f| f.downcase }
87
+ forced = [*options[:force_inclusion]].compact.collect { |f| f.to_s.downcase }
89
88
 
90
89
  @method_details, @missing_methods = [], []
91
90
 
@@ -94,7 +93,7 @@ module DataShift
94
93
  raw_col_data = col_data.to_s
95
94
 
96
95
  if(raw_col_data.nil? or raw_col_data.empty?)
97
- logger.warn("Column list contains empty or null columns")
96
+ logger.warn("Column list contains empty or null column at index #{col_index}")
98
97
  @method_details << nil
99
98
  next
100
99
  end
@@ -103,10 +102,10 @@ module DataShift
103
102
 
104
103
  md = MethodDictionary::find_method_detail( klass, raw_col_name )
105
104
 
106
- # TODO be nice if we could cheeck that the assoc on klass responds to the specified
105
+ # TODO be nice if we could check that the assoc on klass responds to the specified
107
106
  # lookup key now (nice n early)
108
107
  # active_record_helper = "find_by_#{lookup}"
109
- if(md.nil? && options[:include_all] || forced.include?(raw_col_name.downcase))
108
+ if(md.nil? && (options[:include_all] || forced.include?(raw_col_name.downcase)) )
110
109
  md = MethodDictionary::add(klass, raw_col_name)
111
110
  end
112
111
 
@@ -149,7 +148,9 @@ module DataShift
149
148
 
150
149
  # Returns true if discovered methods contain every operator in mandatory_list
151
150
  def contains_mandatory?( mandatory_list )
152
- [ [*mandatory_list] - operator_names].flatten.empty?
151
+ a = [*mandatory_list].collect { |f| f.downcase }
152
+ b = operator_names.collect { |f| f.downcase }
153
+ (a - b).empty?
153
154
  end
154
155
 
155
156
  def missing_mandatory( mandatory_list )
@@ -31,7 +31,7 @@ module DataShift
31
31
  record.send(op, value.send( f) )
32
32
  break
33
33
  rescue => e
34
- #puts "DEBUG: insistent_assignment: #{e.inspect}"
34
+ puts "DEBUG: insistent_assignment: #{e.inspect}"
35
35
  if f == Populator::insistent_method_list.last
36
36
  puts "I'm sorry I have failed to assign [#{value}] to #{operator}"
37
37
  raise "I'm sorry I have failed to assign [#{value}] to #{operator}" unless value.nil?
@@ -86,8 +86,8 @@ module DataShift
86
86
 
87
87
  include DataShift::CsvLoading
88
88
 
89
- def initialize(klass, object = nil, options = {})
90
- super( klass, object, options )
89
+ def initialize(klass, find_operators = true, object = nil, options = {})
90
+ super( klass, find_operators, object, options )
91
91
  raise "Cannot load - failed to create a #{klass}" unless @load_object
92
92
  end
93
93
 
@@ -44,7 +44,6 @@ module DataShift
44
44
  puts "\n\n\nLoading from Excel file: #{file_name}"
45
45
 
46
46
  sheet_number = options[:sheet_number] || 0
47
-
48
47
 
49
48
  @sheet = @excel.worksheet( sheet_number )
50
49
 
@@ -66,14 +65,11 @@ module DataShift
66
65
  end
67
66
 
68
67
  raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" if(@headers.empty?)
69
-
70
68
 
71
69
  # Create a method_mapper which maps list of headers into suitable calls on the Active Record class
72
70
  # For example if model has an attribute 'price' will map columns called Price, price, PRICE etc to this attribute
73
71
  populate_method_mapper_from_headers( @headers, options )
74
72
 
75
- @method_mapper
76
-
77
73
  logger.info "Excel Loader processing #{@sheet.num_rows} rows"
78
74
 
79
75
  loaded_objects.clear
@@ -105,10 +101,9 @@ module DataShift
105
101
 
106
102
  # Iterate over method_details, working on data out of associated Excel column
107
103
  @method_mapper.method_details.each do |method_detail|
108
-
109
-
104
+
110
105
  next unless method_detail # TODO populate unmapped with a real MethodDetail that is 'null' and create is_nil
111
-
106
+
112
107
  value = row[method_detail.column_index]
113
108
 
114
109
  contains_data = true unless(value.nil? || value.to_s.empty?)
@@ -155,8 +150,8 @@ module DataShift
155
150
 
156
151
  include ExcelLoading
157
152
 
158
- def initialize(klass, object = nil, options = {})
159
- super( klass, object, options )
153
+ def initialize(klass, find_operators = true, object = nil, options = {})
154
+ super( klass, find_operators, object, options )
160
155
  raise "Cannot load - failed to create a #{klass}" unless @load_object
161
156
  end
162
157
 
@@ -39,25 +39,25 @@ module DataShift
39
39
  #
40
40
  # Options to drive building the method dictionary for a class, enabling headers to be mapped to operators on that class.
41
41
  #
42
+ # find_operators [default = true] : Populate method dictionary with operators and method details
43
+ #
42
44
  # Options
43
- # :load [default = true] : Load the method dictionary for object_class
44
45
  #
45
46
  # :reload : Force load of the method dictionary for object_class even if already loaded
46
- # :instance_methods : Include setter type instance methods for assignment as well as AR columns
47
-
48
-
49
- def initialize(object_class, object = nil, options = {})
47
+ # :instance_methods : Include setter/delegate style instance methods for assignment, as well as AR columns
48
+ #
49
+ def initialize(object_class, find_operators = true, object = nil, options = {})
50
50
  @load_object_class = object_class
51
-
51
+
52
52
  # Gather names of all possible 'setter' methods on AR class (instance variables and associations)
53
- unless(MethodDictionary::for?(object_class) && options[:reload] == false)
54
- #puts "Building Method Dictionary for class #{object_class}"
53
+ if((find_operators && !MethodDictionary::for?(object_class)) || options[:reload])
54
+ puts "Building Method Dictionary for class #{object_class}"
55
55
  DataShift::MethodDictionary.find_operators( @load_object_class, :reload => options[:reload], :instance_methods => options[:instance_methods] )
56
56
 
57
57
  # Create dictionary of data on all possible 'setter' methods which can be used to
58
58
  # populate or integrate an object of type @load_object_class
59
59
  DataShift::MethodDictionary.build_method_details(@load_object_class)
60
- end if(options[:load] || options[:reload])
60
+ end
61
61
 
62
62
  @method_mapper = DataShift::MethodMapper.new
63
63
  @config = options.dup # clone can cause issues like 'can't modify frozen hash'
@@ -152,10 +152,10 @@ module DataShift
152
152
  raise MappingDefinitionError, "Missing mappings for columns : #{@method_mapper.missing_methods.join(",")}" if(strict)
153
153
  end
154
154
 
155
- unless(@method_mapper.contains_mandatory?(mandatory) )
156
- @method_mapper.missing_mandatory(mandatory).each { |e| puts "ERROR: Mandatory column missing - expected column '#{e}'" }
155
+ unless(mandatory.empty? || @method_mapper.contains_mandatory?(mandatory) )
156
+ @method_mapper.missing_mandatory(mandatory).each { |er| puts "ERROR: Mandatory column missing - expected column '#{er}'" }
157
157
  raise MissingMandatoryError, "Mandatory columns missing - please fix and retry."
158
- end unless(mandatory.empty?)
158
+ end
159
159
 
160
160
  @method_mapper
161
161
  end
@@ -184,6 +184,7 @@ module DataShift
184
184
  prepare_data(method_detail, data)
185
185
  process()
186
186
  else
187
+ puts "No matching method found for column #{column_name}"
187
188
  @load_object.errors.add(:base, "No matching method found for column #{column_name}")
188
189
  end
189
190
  end
@@ -20,20 +20,16 @@ module DataShift
20
20
 
21
21
  attr_writer :attach_to_field
22
22
  attr_reader :attachment_path, :loading_files_cache
23
+
23
24
 
24
-
25
- # If we have instantiated a method detail based on the attch to class and fields
26
- # return that otherwise return the raw format of :attach_to_find_by_field
27
-
28
- def attach_to_field
29
- @attach_to_method_detail || @attach_to_field
30
- end
31
-
25
+ # Constructor
26
+ #
32
27
  # Options
33
-
28
+ #
34
29
  # => :attach_to_klass
35
- # A class that has a relationship with - has_many, has_one or belongs_to - the attachment
30
+ # A class that has a relationship with the attachment (has_many, has_one or belongs_to etc)
36
31
  # The instance of :attach_to_klass can be searched for and the new attachment assigned.
32
+ #
37
33
  # Examples
38
34
  # Owner has_many pdfs and mp3 files as Digitals .... :attach_to_klass = Owner
39
35
  # User has a single image used as an avatar ... :attach_to_klass = User
@@ -41,6 +37,7 @@ module DataShift
41
37
  # => :attach_to_find_by_field
42
38
  # For the :attach_to_klass, this is the field used to search for the parent
43
39
  # object to assign the new attachment to.
40
+ #
44
41
  # Examples
45
42
  # Owner has a unique 'name' field ... :attach_to_find_by_field = :name
46
43
  # User has a unique 'login' field ... :attach_to_klass = :login
@@ -48,27 +45,31 @@ module DataShift
48
45
  # => :attach_to_field
49
46
  # Attribute/association to assign attachment to on :attach_to_klass.
50
47
  # Examples
48
+ #
51
49
  # :attach_to_field => digitals : Owner.digitals = attachment
52
50
  # :attach_to_field => avatar : User.avatar = attachment
53
51
  #
54
52
  #
55
- def initialize(attachment_klazz, attachment = nil, options = {})
53
+ def initialize(attachment_klazz, find_operators = true, attachment = nil, options = {})
56
54
 
57
55
  init_from_options( options )
58
-
59
- opts = options.merge(:load => false)
60
-
61
- super( attachment_klazz, attachment, opts )
56
+
57
+ super( attachment_klazz, find_operators, attachment, options.dup )
62
58
 
63
59
  puts "Attachment Class is #{load_object_class}" if(@verbose)
64
60
 
65
61
  raise "Failed to create Attachment for loading" unless @load_object
66
62
  end
63
+
67
64
 
65
+ # Options
66
+ # :reload
67
+ # :attach_to_klass, :attach_to_field, :attach_to_find_by_field
68
+ #
68
69
  def init_from_options( options )
69
-
70
- @attach_to_klass = options[:attach_to_klass] || @attach_to_klass || nil
71
70
 
71
+ @attach_to_klass = options[:attach_to_klass] || @attach_to_klass || nil
72
+
72
73
  unless(@attach_to_klass.nil? || (MethodDictionary::for?(@attach_to_klass) && options[:reload] == false))
73
74
  #puts "Building Method Dictionary for class #{object_class}"
74
75
  DataShift::MethodDictionary.find_operators( @attach_to_klass, :reload => options[:reload], :instance_methods => true )
@@ -86,6 +87,15 @@ module DataShift
86
87
  end
87
88
  end
88
89
 
90
+
91
+ # If we have instantiated a method detail based on the attach to class and fields
92
+ # return that otherwise return the raw format of :attach_to_find_by_field
93
+
94
+ def attach_to_field
95
+ @attach_to_method_detail || @attach_to_field
96
+ end
97
+
98
+
89
99
  # This version creates attachments and also attaches them to instances of :attach_to_klazz
90
100
  #
91
101
  # Options
@@ -125,7 +135,7 @@ module DataShift
125
135
 
126
136
  record = nil
127
137
 
128
- puts "try to find record where #{attach_to_find_by_field} == #{base_name}"
138
+ puts "Attempting to find matching record where #{attach_to_find_by_field} ~= #{base_name}"
129
139
  record = get_record_by(attach_to_klass, attach_to_find_by_field, base_name, split_on)
130
140
 
131
141
  if(record)
@@ -139,12 +149,11 @@ module DataShift
139
149
 
140
150
  # Check if attachment must have an associated record
141
151
  if(record)
142
- puts "now create attachment"
143
152
  reset()
144
153
 
145
154
  create_attachment(@load_object_class, file_name, record, attach_to_field, options)
146
155
 
147
- puts "Added Attachment #{File.basename(file_name)} to #{record.send(attach_to_find_by_field)} : #{record.id}" if(@verbose)
156
+ puts "Added Attachment #{File.basename(file_name)} to #{record.send(attach_to_find_by_field)}(id : #{record.id})" if(@verbose)
148
157
  end
149
158
 
150
159
  end
@@ -153,7 +162,7 @@ module DataShift
153
162
  FileUtils.mkdir_p('MissingAttachmentRecords') unless File.directory?('MissingAttachmentRecords')
154
163
 
155
164
  puts "WARNING : #{missing_records.size} of #{loading_files_cache.size} files could not be attached to a #{@load_object_class}"
156
- puts "For your convenience a copy of files with MISSING #{@load_object_class} : ./MissingAttachmentRecords"
165
+ puts "For your convenience files with MISSING #{attach_to_klass} have been copied to : MissingAttachmentRecords"
157
166
  missing_records.each do |i|
158
167
  puts "Copying #{i} to MissingAttachmentRecords folder" if(options[:verbose])
159
168
  FileUtils.cp( i, 'MissingAttachmentRecords') unless(options[:dummy] == 'true')
@@ -56,7 +56,7 @@ module DataShift
56
56
  #
57
57
  # Pass through hash of attributes to klass initializer
58
58
  #
59
- # :has_attached_file_attribute
59
+ # :has_attached_file_name
60
60
  #
61
61
  # Paperclip attachment name defined with macro 'has_attached_file :name'
62
62
  #
@@ -71,7 +71,7 @@ module DataShift
71
71
  #
72
72
  def create_attachment(klass, attachment_path, record = nil, attach_to_record_field = nil, options = {})
73
73
 
74
- has_attached_file_attribute = options[has_attached_file_attribute] ? options[:has_attached_file_attribute].to_sym : :attachment
74
+ has_attached_file_attribute = options[:has_attached_file_name] ? options[:has_attached_file_name].to_sym : :attachment
75
75
 
76
76
  attributes = { has_attached_file_attribute => get_file(attachment_path) }
77
77
 
@@ -81,6 +81,7 @@ module DataShift
81
81
 
82
82
  #attributes.merge!(attach_to_record_field.to_sym => record) if(record && attach_to_record_field)
83
83
 
84
+ puts attributes.inspect
84
85
  begin
85
86
 
86
87
  @attachment = klass.new(attributes, :without_protection => true)
@@ -92,11 +93,12 @@ module DataShift
92
93
  attach_to_record_field.assign(record, @attachment)
93
94
  else
94
95
  # assume its not a has_many and try basic send
95
- record.send(attach_to_record_field + '=', @attachment)
96
+ record.send("#{attach_to_record_field}=", @attachment)
96
97
  end if(record && attach_to_record_field)
97
98
 
98
99
  else
99
100
  puts "ERROR : Problem saving to DB : #{@attachment.inspect}"
101
+ puts @attachment.errors.messages.inspect
100
102
  end
101
103
 
102
104
  @attachment
@@ -14,9 +14,6 @@ module DataShift
14
14
 
15
15
  include DataShift::Paperclip
16
16
 
17
- def initialize(attachment_klazz, attachment = nil, options = {})
18
- super( attachment_klazz, attachment, options )
19
- end
20
17
 
21
18
  # Note the paperclip attachment model defines the storage path via something like :
22
19
  #
@@ -33,15 +30,17 @@ module DataShift
33
30
  # :viewable_record
34
31
  #
35
32
  def create_attachment(klass, attachment_path, record = nil, attach_to_record_field = nil, options = {})
36
-
37
- attachment_options = options.dup
38
-
39
- attributes = {:alt => (options[:alt] || "") }
40
-
41
- attributes[:position] = (!options[:position] && record and record.respond_to?(:images)) ? record.images.length : 0
33
+
34
+ image_attributes = { :attributes =>
35
+ { :alt => (options[:alt] || ""),
36
+ :position => (!options[:position] && record and record.respond_to?(:images)) ? record.images.length : 0
37
+ }
38
+ }
42
39
 
43
- attachment_options.merge!( attributes )
44
-
40
+ attachment_options = options.dup.merge(image_attributes)
41
+
42
+ #puts "DEBUG : create_attachment options : #{attachment_options.inspect}"
43
+
45
44
  super(klass, attachment_path, record, attach_to_record_field, attachment_options)
46
45
  end
47
46
 
@@ -63,11 +63,11 @@ module Datashift
63
63
  logger.info("INFO: Using loader : #{loader.class}")
64
64
  rescue
65
65
  logger.error("INFO: No specific #{model}Loader found - using generic ExcelLoader")
66
- loader = DataShift::ExcelLoader.new(klass)
66
+ loader = DataShift::ExcelLoader.new(klass, true)
67
67
  end
68
68
  else
69
69
  logger.info("No Loader specified - using generic ExcelLoader")
70
- loader = DataShift::ExcelLoader.new(klass)
70
+ loader = DataShift::ExcelLoader.new(klass, true)
71
71
  end
72
72
 
73
73
  logger.info("ARGS #{options.inspect}")
@@ -22,11 +22,32 @@ module Datashift
22
22
 
23
23
  include DataShift::Logging
24
24
 
25
- desc "attach", "Attach files from a directory\nThe attachment file names must contain the lookup info within them.
26
- The instance of :attach_to_klass can be searched for and the new attachment assigned.
25
+ desc "attach", "Create paperclip attachments and attach to a Model from files in a directory.
26
+ This is specifically for the use case where the paperclip attachments are stored in a class, such as Image, Icon, Asset,
27
+ and this class has a relationship, such as belongs_to, with another class, such as Product, User, Document.
28
+
29
+ Each matching file is used to create an instance of the paperclip attachment, given by :attachment_klass.
30
+
31
+ The class with the relationship, can be specified via :attach_to_klass
32
+
27
33
  Examples
28
- Owner has_many pdfs and mp3 files as Digitals .... :attach_to_klass = Owner
29
- User has a single image used as an avatar ... :attach_to_klass = User"
34
+ Owner has_many pdfs and mp3 files as Digitals .... :attachment_klass = Digital and :attach_to_klass = Owner
35
+ User has a single Image used as an avatar ... attachment_klass = Image and :attach_to_klass = User
36
+
37
+ The file name is used to lookup the instance of :attach_to_klass to assign the new attachment to, via :attach_to_find_by_field
38
+
39
+ So say we have a file called smithj_avatar.gif, and we want to lookup Users by login
40
+
41
+ :attach_to_find_by_field = login => Run a loookup based on find_by_login == 'smithj'
42
+
43
+ Once instance of :attach_to_klass found, the new attachment is assigned.
44
+
45
+ The attribute to assign new attachment to is gtiven by :attach_to_field
46
+
47
+ Examples
48
+ :attach_to_field => digitals : Owner.digitals = attachment(Digital)
49
+ :attach_to_field => avatar : User.avatar = attachment(Image)"
50
+
30
51
 
31
52
  # :dummy => dummy run without actual saving to DB
32
53
  method_option :input, :aliases => '-i', :required => true, :desc => "The input path containing images "
@@ -35,13 +56,11 @@ module Datashift
35
56
  method_option :recursive, :aliases => '-r', :type => :boolean, :desc => "Scan sub directories of input for images"
36
57
 
37
58
  method_option :attachment_klass, :required => true, :aliases => '-a', :desc => "Ruby Class name of the Attachment e.g Image, Icon"
38
- method_option :attach_to_klass, :required => true, :aliases => '-k', :desc => "A class that has a relationship with the attachment (has_many, has_one, belongs_to)"
39
-
40
-
41
- method_option :attach_to_field, :required => true, :aliases => '-f', :desc => "Attachment belongs to field e.g Product.image, Blog.digital"
42
59
 
60
+ method_option :attach_to_klass, :required => true, :aliases => '-k', :desc => "A class that has a relationship with the attachment (has_many, has_one, belongs_to)"
43
61
  method_option :attach_to_find_by_field, :required => true, :aliases => '-l', :desc => "The field to use to find the :attach_to_klass record"
44
-
62
+ method_option :attach_to_field, :required => true, :aliases => '-f', :desc => "Attachment belongs to field e.g Product.image, Blog.digital"
63
+
45
64
 
46
65
  # => :attach_to_find_by_field
47
66
  # For the :attach_to_klass, this is the field used to search for the parent
@@ -31,9 +31,6 @@ describe 'Excel Loader' do
31
31
  Category.find_or_create_by_reference(cat)
32
32
  end
33
33
 
34
- DataShift::MethodDictionary.find_operators( Category )
35
-
36
- DataShift::MethodDictionary.build_method_details( Category )
37
34
 
38
35
  end
39
36
 
@@ -57,6 +54,11 @@ describe 'Excel Loader' do
57
54
 
58
55
  it "should process multiple associationss from single column" do
59
56
 
57
+
58
+ DataShift::MethodDictionary.find_operators( Category )
59
+
60
+ DataShift::MethodDictionary.build_method_details( Category )
61
+
60
62
  Project.find_by_title('001').should be_nil
61
63
  count = Project.count
62
64
 
@@ -8,25 +8,34 @@
8
8
  # and a classes different types of assignment operators
9
9
  #
10
10
  require File.join(File.dirname(__FILE__), 'spec_helper')
11
-
11
+
12
+ require 'method_dictionary'
13
+
12
14
  describe 'Method Dictionary' do
13
15
 
16
+
14
17
  include_context "ActiveRecordTestModelsConnected"
15
18
 
19
+ include DataShift
16
20
 
17
21
  before(:each) do
18
22
  MethodDictionary.clear
19
- MethodDictionary.find_operators( Project )
20
- MethodDictionary.find_operators( Milestone )
21
23
  end
22
24
 
23
25
  it "should store dictionary for multiple AR models" do
26
+
27
+ MethodDictionary.find_operators( Project )
28
+ MethodDictionary.find_operators( Milestone )
29
+
24
30
  MethodDictionary.assignments.size.should == 2
25
31
  MethodDictionary.has_many.size.should == 2
26
32
  end
27
33
 
28
34
  it "should populate method dictionary for a given AR model" do
29
35
 
36
+ MethodDictionary.find_operators( Project )
37
+ MethodDictionary.find_operators( Milestone )
38
+
30
39
  MethodDictionary.has_many.should_not be_empty
31
40
  MethodDictionary.has_many[Project].should include('milestones')
32
41
 
@@ -48,6 +57,8 @@ describe 'Method Dictionary' do
48
57
 
49
58
  it "should populate assigment members without the equivalent association names" do
50
59
 
60
+ MethodDictionary.find_operators( Project )
61
+
51
62
  # we should remove has-many & belongs_to from basic assignment set as they require a DB lookup
52
63
  # or a Model.create call, not a simple assignment
53
64
 
@@ -58,6 +69,9 @@ describe 'Method Dictionary' do
58
69
 
59
70
  it "should populate assignment operators for method details for different forms of a column name" do
60
71
 
72
+ MethodDictionary.find_operators( Project )
73
+ MethodDictionary.find_operators( Milestone )
74
+
61
75
  MethodDictionary.build_method_details( Project )
62
76
 
63
77
  [:value_as_string, 'value_as_string', "VALUE as_STRING", "value as string"].each do |format|
@@ -83,6 +97,8 @@ describe 'Method Dictionary' do
83
97
 
84
98
  it "should populate column types for assignment operators in method details" do
85
99
 
100
+ MethodDictionary.find_operators( Project )
101
+
86
102
  MethodDictionary.build_method_details( Project )
87
103
 
88
104
  [:value_as_string, 'value_as_string', "VALUE as_STRING", "value as string"].each do |format|
@@ -101,6 +117,8 @@ describe 'Method Dictionary' do
101
117
 
102
118
  it "should populate required Class for assignment operators based on column type" do
103
119
 
120
+ MethodDictionary.find_operators( Project )
121
+
104
122
  MethodDictionary.build_method_details( Project )
105
123
 
106
124
  [:value_as_string, 'value_as_string', "VALUE as_STRING", "value as string"].each do |format|
@@ -116,6 +134,9 @@ describe 'Method Dictionary' do
116
134
 
117
135
  it "should populate belongs_to operator for method details for different forms of a column name" do
118
136
 
137
+ MethodDictionary.find_operators( Project )
138
+ MethodDictionary.find_operators( Milestone )
139
+
119
140
  MethodDictionary.build_method_details( Project )
120
141
  MethodDictionary.build_method_details( Milestone )
121
142
 
@@ -184,10 +205,24 @@ describe 'Method Dictionary' do
184
205
  method_details.operator_class.should == LongAndComplexTableLinkedToVersion
185
206
  end
186
207
  end
208
+
209
+ it "should return false on for?(klass) if find_operators hasn't been called for klass" do
210
+ MethodDictionary.clear
211
+ MethodDictionary::for?(Project).should == false
212
+ MethodDictionary::find_operators(Project)
213
+ MethodDictionary::for?(Project).should == true
214
+
215
+ end
187
216
 
188
-
217
+ it "should return false on for?(klass) if find_operators hasn't been called for klass" do
218
+ MethodDictionary.clear
219
+ MethodDictionary::for?(Project).should == false
220
+ end
221
+
189
222
  it "should find has_many operator for method details" do
190
-
223
+
224
+ MethodDictionary.find_operators( Project )
225
+
191
226
  MethodDictionary.build_method_details( Project )
192
227
 
193
228
  [:milestones, "Mile Stones", 'mileSTONES', 'MileStones'].each do |format|
@@ -208,6 +243,9 @@ describe 'Method Dictionary' do
208
243
 
209
244
 
210
245
  it "should return nil when non existent column name" do
246
+
247
+ MethodDictionary.find_operators( Project )
248
+
211
249
  ["On sale", 'on_sale'].each do |format|
212
250
  detail = MethodDictionary.find_method_detail( Project, format )
213
251
 
@@ -221,11 +259,16 @@ describe 'Method Dictionary' do
221
259
  end
222
260
 
223
261
  it "should not by default map setter methods" do
262
+ MethodDictionary.find_operators( Milestone )
263
+
224
264
  MethodDictionary.assignments[Milestone].should_not include('title')
225
265
  end
226
266
 
227
267
  it "should support reload and inclusion of setter methods" do
228
268
 
269
+ MethodDictionary.find_operators( Project )
270
+ MethodDictionary.find_operators( Milestone )
271
+
229
272
  MethodDictionary.assignments[Milestone].should_not include('title')
230
273
 
231
274
  MethodDictionary.find_operators( Milestone, :reload => true, :instance_methods => true )
@@ -38,7 +38,7 @@ describe 'PaperClip Bulk Loader' do
38
38
  end
39
39
 
40
40
  it "should create a new paperclip loader and define attachment class" do
41
- loader = DataShift::Paperclip::AttachmentLoader.new(@attachment_klass, nil, @common_options)
41
+ loader = DataShift::Paperclip::AttachmentLoader.new(@attachment_klass, true, nil, @common_options)
42
42
 
43
43
  loader.load_object_class.should == Digital
44
44
  loader.load_object.should be_a Digital
@@ -50,7 +50,7 @@ describe 'PaperClip Bulk Loader' do
50
50
 
51
51
  opts = { :attach_to_klass => Owner }.merge(@common_options)
52
52
 
53
- loader = DataShift::Paperclip::AttachmentLoader.new(@attachment_klass, nil, opts)
53
+ loader = DataShift::Paperclip::AttachmentLoader.new(@attachment_klass, true, nil, opts)
54
54
 
55
55
  loader.attach_to_klass.should == Owner
56
56
  end
metadata CHANGED
@@ -1,58 +1,50 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: datashift
3
- version: !ruby/object:Gem::Version
4
- version: 0.10.2
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
5
+ version: 0.11.0
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Thomas Statter
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-21 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
12
+
13
+ date: 2012-10-23 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
15
16
  name: spreadsheet
16
- requirement: !ruby/object:Gem::Requirement
17
+ requirement: &id001 !ruby/object:Gem::Requirement
17
18
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
22
23
  type: :runtime
23
24
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- - !ruby/object:Gem::Dependency
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
31
27
  name: rubyzip
32
- requirement: !ruby/object:Gem::Requirement
28
+ requirement: &id002 !ruby/object:Gem::Requirement
33
29
  none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
38
34
  type: :runtime
39
35
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
46
- description: Comprehensive tools to import/export between Excel/CSV and ActiveRecord
47
- databases, Rails apps, and any Ruby project.
36
+ version_requirements: *id002
37
+ description: Comprehensive tools to import/export between Excel/CSV and ActiveRecord databases, Rails apps, and any Ruby project.
48
38
  email: rubygems@autotelik.co.uk
49
39
  executables: []
40
+
50
41
  extensions: []
51
- extra_rdoc_files:
42
+
43
+ extra_rdoc_files:
52
44
  - LICENSE.txt
53
45
  - README.markdown
54
46
  - README.rdoc
55
- files:
47
+ files:
56
48
  - .document
57
49
  - LICENSE.txt
58
50
  - README.markdown
@@ -229,28 +221,31 @@ files:
229
221
  - tasks/file_tasks.rake
230
222
  - tasks/word_to_seedfu.rake
231
223
  homepage: http://github.com/autotelik/datashift
232
- licenses:
224
+ licenses:
233
225
  - MIT
234
226
  post_install_message:
235
227
  rdoc_options: []
236
- require_paths:
228
+
229
+ require_paths:
237
230
  - lib
238
- required_ruby_version: !ruby/object:Gem::Requirement
231
+ required_ruby_version: !ruby/object:Gem::Requirement
239
232
  none: false
240
- requirements:
241
- - - ! '>='
242
- - !ruby/object:Gem::Version
243
- version: '0'
244
- required_rubygems_version: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: "0"
237
+ required_rubygems_version: !ruby/object:Gem::Requirement
245
238
  none: false
246
- requirements:
247
- - - ! '>='
248
- - !ruby/object:Gem::Version
249
- version: '0'
239
+ requirements:
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ version: "0"
250
243
  requirements: []
244
+
251
245
  rubyforge_project:
252
246
  rubygems_version: 1.8.24
253
247
  signing_key:
254
248
  specification_version: 3
255
249
  summary: Shift data betwen Excel/CSV and any Ruby app
256
250
  test_files: []
251
+