lib/spreadsheet_architect/utils.rb in spreadsheet_architect-2.1.2 vs lib/spreadsheet_architect/utils.rb in spreadsheet_architect-3.0.0

- old
+ new

@@ -1,147 +1,136 @@ module SpreadsheetArchitect module Utils - def self.str_humanize(str, capitalize = true) - str = str.sub(/\A_+/, '').gsub(/[_\.]/,' ').sub(' rescue nil','') - if capitalize - str = str.gsub(/(\A|\ )\w/){|x| x.upcase} + def self.get_cell_data(options, klass) + if options[:data] && options[:instances] + raise SpreadsheetArchitect::Exceptions::MultipleDataSourcesError + elsif options[:data] + data = options[:data] end - return str - end - def self.get_cell_data(options={}, klass) - self.check_options_types + if !options[:data] && options[:headers] == true + headers = [] + needs_headers = true + elsif options[:headers].is_a?(Array) + headers = options[:headers] + else + headers = false + end - if klass.name == 'SpreadsheetArchitect' - if !options[:data] - raise SpreadsheetArchitect::Exceptions::NoDataError - end - - if options[:headers] && options[:headers].is_a?(Array) && !options[:headers].empty? - headers = options[:headers] - else - headers = false - end - - data = options[:data] + if options[:column_types] + column_types = options[:column_types] else - has_custom_columns = options[:spreadsheet_columns] || klass.instance_methods.include?(:spreadsheet_columns) + column_types = [] + needs_column_types = true + end - if !options[:instances] && defined?(ActiveRecord) && klass.ancestors.include?(ActiveRecord::Base) - options[:instances] = klass.where(nil).to_a # triggers the relation call, not sure how this works but it does - end - + if !data if !options[:instances] - raise SpreadsheetArchitect::Exceptions::NoInstancesError + if is_ar_model?(klass) + options[:instances] = klass.where(nil).to_a # triggers the relation call, not sure how this works but it does + else + raise SpreadsheetArchitect::Exceptions::NoDataError + end end - if options[:headers].nil? - headers = klass::SPREADSHEET_OPTIONS[:headers] if defined?(klass::SPREADSHEET_OPTIONS) - headers ||= SpreadsheetArchitect.default_options[:headers] - elsif options[:headers].is_a?(Array) - headers = options[:headers] - end - - if headers == false || headers.is_a?(Array) - needs_headers = false - else - headers = true - needs_headers = true - end - - if has_custom_columns - headers = [] if needs_headers - columns = [] - array = options[:spreadsheet_columns] || (options[:instances].empty? ? [] : options[:instances].first.spreadsheet_columns) - array.each_with_index do |x,i| - if x.is_a?(Array) - headers.push(x[0].to_s) if needs_headers - columns.push x[1] - else - headers.push(str_humanize(x.to_s)) if needs_headers - columns.push x - end + if !options[:spreadsheet_columns] && klass != SpreadsheetArchitect && !klass.instance_methods.include?(:spreadsheet_columns) + if is_ar_model?(klass) + the_column_names = klass.column_names + headers = the_column_names.map{|x| str_titleize(x)} if needs_headers + columns = the_column_names.map{|x| x.to_sym} + else + raise SpreadsheetArchitect::Exceptions::SpreadsheetColumnsNotDefinedError.new(klass) end - elsif !has_custom_columns && defined?(ActiveRecord) && klass.ancestors.include?(ActiveRecord::Base) - ignored_columns = ["id","created_at","updated_at","deleted_at"] - the_column_names = (klass.column_names - ignored_columns) - headers = the_column_names.map{|x| str_humanize(x)} if needs_headers - columns = the_column_names.map{|x| x.to_sym} - else - raise SpreadsheetArchitect::Exceptions::SpreadsheetColumnsNotDefinedError, klass end data = [] options[:instances].each do |instance| - if has_custom_columns && !options[:spreadsheet_columns] + if columns + data.push columns.map{|col| col.is_a?(Symbol) ? instance.instance_eval(col.to_s) : col} + else row_data = [] - instance.spreadsheet_columns.each do |x| + + if !options[:spreadsheet_columns] + if klass == SpreadsheetArchitect && !instance.respond_to?(:spreadsheet_columns) + raise SpreadsheetArchitect::Exceptions::SpreadsheetColumnsNotDefinedError.new(instance.class) + else + instance_cols = instance.spreadsheet_columns + end + else + instance_cols = options[:spreadsheet_columns].call(instance) + end + + instance_cols.each_with_index do |x,i| if x.is_a?(Array) + headers.push(x[0].to_s) if needs_headers row_data.push(x[1].is_a?(Symbol) ? instance.instance_eval(x[1].to_s) : x[1]) + if needs_column_types + column_types[i] = x[2] + end else + headers.push(str_titleize(x.to_s)) if needs_headers row_data.push(x.is_a?(Symbol) ? instance.instance_eval(x.to_s) : x) end end + data.push row_data - else - data.push columns.map{|col| col.is_a?(Symbol) ? instance.instance_eval(col.to_s) : col} + + needs_headers = false + needs_column_types = false end + end end if headers && !headers[0].is_a?(Array) headers = [headers] end - return options.merge(headers: headers, data: data, column_types: options[:column_types]) + if column_types.compact.empty? + column_types = nil + end + + return options.merge(headers: headers, data: data, column_types: column_types) end - def self.get_options(options={}, klass) - if options[:headers] - if defined?(klass::SPREADSHEET_OPTIONS) - header_style = deep_clone(SpreadsheetArchitect.default_options[:header_style]).merge(klass::SPREADSHEET_OPTIONS[:header_style] || {}) + def self.get_options(options, klass) + verify_option_types(options) + + if defined?(klass::SPREADSHEET_OPTIONS) + if klass::SPREADSHEET_OPTIONS.is_a?(Hash) + options = SpreadsheetArchitect.default_options.merge( + klass::SPREADSHEET_OPTIONS.merge(options) + ) else - header_style = deep_clone(SpreadsheetArchitect.default_options[:header_style]) + raise SpreadsheetArchitect::Exceptions::InvalidTypeError.new("#{klass}::SPREADSHEET_OPTIONS constant") end - - if options[:header_style] - header_style.merge!(options[:header_style]) - elsif options[:header_style] == false - header_style = false - end else - header_style = false + options = SpreadsheetArchitect.default_options.merge(options) end - if options[:row_style] == false - row_style = false - else - if defined?(klass::SPREADSHEET_OPTIONS) - row_style = deep_clone(SpreadsheetArchitect.default_options[:row_style]).merge(klass::SPREADSHEET_OPTIONS[:row_style] || {}) + if !options[:headers] + options[:header_style] = false + end + + if !options[:sheet_name] + if klass == SpreadsheetArchitect + options[:sheet_name] = 'Sheet1' else - row_style = deep_clone(SpreadsheetArchitect.default_options[:row_style]) - end + options[:sheet_name] = klass.name - if options[:row_style] - row_style.merge!(options[:row_style]) + if options[:sheet_name].respond_to?(:pluralize) + options[:sheet_name] = options[:sheet_name].pluralize + end end end - if defined?(klass::SPREADSHEET_OPTIONS) - sheet_name = options[:sheet_name] || klass::SPREADSHEET_OPTIONS[:sheet_name] || SpreadsheetArchitect.default_options[:sheet_name] - else - sheet_name = options[:sheet_name] || SpreadsheetArchitect.default_options[:sheet_name] - end - - sheet_name ||= (klass.name == 'SpreadsheetArchitect' ? 'Sheet1' : klass.name) - - return options.merge(header_style: header_style, row_style: row_style, sheet_name: sheet_name) + return options end def self.convert_styles_to_ods(styles={}) styles = {} unless styles.is_a?(Hash) - styles = self.stringify_keys(styles) + styles = stringify_keys(styles) property_styles = {} text_styles = {} text_styles['font-weight'] = styles.delete('bold') ? 'bold' : styles.delete('font-weight') @@ -173,51 +162,57 @@ return property_styles end private - def self.deep_clone(x) - Marshal.load(Marshal.dump(x)) + def self.is_ar_model?(klass) + defined?(ActiveRecord) && klass.ancestors.include?(ActiveRecord::Base) end - def self.check_type(options, option_name, type) - unless options[option_name].nil? - valid = false + def self.str_titleize(str) + str = str.sub(/\A_+/, '') + .gsub(/[_\.]/,' ') + .sub(' rescue nil','') + .gsub(/(\A|\ )\w/){|x| x.upcase} + return str + end + + def self.check_option_type(options, option_name, type) + val = options[option_name] + + if val if type.is_a?(Array) - valid = type.any?{|t| options[option_name].is_a?(t)} - elsif options[option_name].is_a?(type) - valid = true + invalid = type.all?{|t| !val.is_a?(t) } + elsif !val.is_a?(type) + invalid = true end - if valid - raise SpreadsheetArchitect::Exceptions::IncorrectTypeError option_name + if invalid + raise SpreadsheetArchitect::Exceptions::InvalidTypeError.new(":#{option_name} option") end end end - def self.check_options_types(options={}) - self.check_type(options, :spreadsheet_columns, Array) - self.check_type(options, :instances, Array) - self.check_type(options, :headers, [TrueClass, FalseClass, Array]) - self.check_type(options, :sheet_name, String) - self.check_type(options, :header_style, Hash) - self.check_type(options, :row_style, Hash) - self.check_type(options, :column_styles, Array) - self.check_type(options, :range_styles, Array) - self.check_type(options, :merges, Array) - self.check_type(options, :borders, Array) - self.check_type(options, :column_widths, Array) + def self.verify_option_types(options) + check_option_type(options, :spreadsheet_columns, Proc) + check_option_type(options, :data, Array) + check_option_type(options, :instances, Array) + check_option_type(options, :headers, [TrueClass, Array]) + check_option_type(options, :header_style, Hash) + check_option_type(options, :row_style, Hash) + check_option_type(options, :column_styles, Array) + check_option_type(options, :range_styles, Array) + check_option_type(options, :merges, Array) + check_option_type(options, :borders, Array) + check_option_type(options, :column_widths, Array) end - # only converts the first 2 levels def self.stringify_keys(hash={}) new_hash = {} hash.each do |k,v| if v.is_a?(Hash) - v.each do |k2,v2| - new_hash[k2.to_s] = v2 - end + new_hash[k.to_s] = self.stringify_keys(v) else new_hash[k.to_s] = v end end return new_hash