Skip to content

Commit

Permalink
support formulas #56
Browse files Browse the repository at this point in the history
  • Loading branch information
tom statter committed Mar 10, 2016
1 parent 867db79 commit e1730fc
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 48 deletions.
9 changes: 9 additions & 0 deletions lib/datashift.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ def self.require_libraries
end
end

if(DataShift::Guards.jruby?)
require 'jexcel_file'
JExcelFile
else
require 'spreadsheet'
require 'spreadsheet_extensions'
Spreadsheet
end

end

# Load all the datashift rake tasks and make them available throughout app
Expand Down
98 changes: 50 additions & 48 deletions lib/datashift/populator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ module DataShift
Struct.new("Substitution", :pattern, :replacement)

class Populator

include DataShift::Logging

def self.insistent_method_list
@insistent_method_list ||= [:to_s, :to_i, :to_f, :to_b]
end

# When looking up an association, when no field provided, try each of these in turn till a match
# i.e find_by_name, find_by_title, find_by_id
def self.insistent_find_by_list
Expand All @@ -44,32 +44,32 @@ def self.header_default_data

attr_reader :current_value, :original_value_before_override
attr_reader :current_col_type

attr_reader :current_attribute_hash
attr_reader :current_method_detail
def initialize

def initialize
@current_value = nil
@current_method_detail = nil
@original_value_before_override = nil
@current_attribute_hash = {}

end

# Convert DSL string forms into a hash
# e.g
#
# "{:name => 'autechre'}" => Hash['name'] = autechre'
# "{:cost_price => '13.45', :price => 23, :sale_price => 4.23 }"

def self.string_to_hash( str )
h = {}
str.gsub(/[{}:]/,'').split(', ').map do |e|
str.gsub(/[{}:]/,'').split(', ').map do |e|
k,v = e.split('=>')

k.strip!
v.strip!

if( v.match(/['"]/) )
h[k] = v.gsub(/["']/, '')
elsif( v.match(/^\d+$|^\d*\.\d+$|^\.\d+$/) )
Expand All @@ -79,10 +79,10 @@ def self.string_to_hash( str )
end
h
end

h
end

# Set member variables to hold details, value and optional attributes,
# to be set on the 'value' once created
#
Expand All @@ -93,32 +93,33 @@ def self.string_to_hash( str )
def prepare_data(method_detail, value)

raise NilDataSuppliedError.new("No method detail supplied for prepare_data") unless(method_detail)

begin
@prepare_data_const_regexp ||= Regexp.new( Delimiters::attribute_list_start + ".*" + Delimiters::attribute_list_end)

if( value.is_a? ActiveRecord::Relation ) # Rails 4 - query no longer returns an array
@current_value = value.to_a
elsif( !DataShift::Guards.jruby? && value.class.ancestors.include?(Spreadsheet::Formula))
@current_value = value.value
elsif( value.class.ancestors.include?(ActiveRecord::Base) || value.is_a?(Array))
@current_value = value
else
@current_value = value.to_s

attribute_hash = @current_value.slice!(@prepare_data_const_regexp)

if(attribute_hash)
#@current_value.chop! # the slice seems to add an extra space/eol

if(attribute_hash)
@current_attribute_hash = Populator::string_to_hash( attribute_hash )
logger.info "Populator for #{@current_value} has attributes #{@current_attribute_hash.inspect}"
end
end

@current_attribute_hash ||= {}

@current_method_detail = method_detail

@current_col_type = @current_method_detail.col_type

operator = method_detail.operator

if(has_override?(operator))
Expand All @@ -143,32 +144,33 @@ def prepare_data(method_detail, value)

rescue => e
logger.error("populator failed to prepare data supplied for operator #{method_detail.operator}")
logger.error("populator stacktrace: #{e.backtrace.join('\\n')}")
logger.error("populator error: #{e.inspect}")
logger.error("populator stacktrace: #{e.backtrace.last}")
raise DataProcessingError.new("opulator failed to prepare data #{value} for operator #{method_detail.operator}")
end

return @current_value, @current_attribute_hash
end

# Main client hook

def prepare_and_assign(method_detail, record, value)

prepare_data(method_detail, value)
prepare_data(method_detail, value)

assign(record)
end

def assign(record)

raise NilDataSuppliedError.new("No method detail - cannot assign data") unless(current_method_detail)

operator = current_method_detail.operator

logger.debug("Populator assign - [#{current_value}] via #{current_method_detail.operator} (#{current_method_detail.operator_type})")

if( current_method_detail.operator_for(:belongs_to) )

insistent_belongs_to(current_method_detail, record, current_value)

elsif( current_method_detail.operator_for(:has_many) )
Expand Down Expand Up @@ -215,9 +217,9 @@ def assign(record)
logger.error("WARNING: No assignment possible on #{record.inspect} using [#{operator}]")
end
end

def insistent_assignment(record, value, operator)

op = operator + '=' unless(operator.include?('='))

begin
Expand All @@ -238,7 +240,7 @@ def insistent_assignment(record, value, operator)
end
end
end

# Attempt to find the associated object via id, name, title ....
def insistent_belongs_to(method_detail, record, value )

Expand Down Expand Up @@ -285,14 +287,14 @@ def insistent_belongs_to(method_detail, record, value )
end
end
end

end
end

def assignment( operator, record, value )

op = operator + '=' unless(operator.include?('='))

begin
record.send(op, value)
rescue => e
Expand All @@ -309,8 +311,8 @@ def assignment( operator, record, value )
end
end
end


# Default values and over rides can be provided in Ruby/YAML ???? config file.
#
# Format :
Expand All @@ -328,16 +330,16 @@ def configure_from(load_object_class, yaml_file)
data = YAML::load( ERB.new( IO.read(yaml_file) ).result )

# TODO - MOVE DEFAULTS TO OWN MODULE

logger.info("Setting Populator defaults: #{data.inspect}")

if(data[load_object_class.name])

deflts = data[load_object_class.name]['datashift_defaults']
default_values.merge!(deflts) if deflts

logger.info("Set Populator default_values: #{default_values.inspect}")

ovrides = data[load_object_class.name]['datashift_overrides']
override_values.merge!(ovrides) if ovrides
logger.info("Set Populator overrides: #{override_values.inspect}")
Expand Down Expand Up @@ -380,34 +382,34 @@ def substitute( operator )
def set_override_value( operator, value )
override_values[operator] = value
end

def override_values
@override_values ||= {}
end

def override_value( operator )
if(override_values[operator])
@original_value_before_override = @current_value

@current_value = @override_values[operator]
end
end


def has_override?( operator )
return override_values.has_key?(operator)
return override_values.has_key?(operator)
end

# Set a default value to be used to populate Model.operator
# Generally defaults will be used when no value supplied.
def set_default_value(operator, value )
default_values[operator] = value
end

def default_values
@default_values ||= {}
end

# Return the default value for supplied operator
def default_value(operator)
default_values[operator]
Expand All @@ -424,19 +426,19 @@ def prefix(operator)
def prefixes
@prefixes ||= {}
end

def set_postfix(operator, value )
postfixes[operator] = value
end

def postfix(operator)
postfixes[operator]
end

def postfixes
@postfixes ||= {}
end

end

end

0 comments on commit e1730fc

Please sign in to comment.