Permalink
Browse files

Refactoring

  • Loading branch information...
1 parent bfc65d6 commit 6e00449177fd2daeb9359db413744d0ead0fd197 @glebm committed Nov 17, 2012
View
3 Rakefile
@@ -13,10 +13,11 @@ task :env do
include ToSpreadsheet::Helpers
end
+desc 'Generate a simple xlsx file'
task :write_test_xlsx => :env do
require 'haml'
path = '/tmp/spreadsheet.xlsx'
html = Haml::Engine.new(File.read('spec/support/table.html.haml')).render
- ToSpreadsheet::Axlsx::Renderer.to_package(html).serialize(path)
+ ToSpreadsheet::Renderer.to_package(html).serialize(path)
puts "Written to #{path}"
end
View
4 lib/to_spreadsheet.rb
@@ -7,8 +7,6 @@
module ToSpreadsheet
class << self
- attr_accessor :context
-
def theme(name, &formats)
@themes ||= {}
if formats
@@ -21,4 +19,4 @@ def theme(name, &formats)
end
require 'to_spreadsheet/themes/default'
-ToSpreadsheet.context = ToSpreadsheet::Context.new.apply ToSpreadsheet.theme(:default)
+ToSpreadsheet::Context.global.format_xls ToSpreadsheet.theme(:default)
View
8 lib/to_spreadsheet/action_pack_renderers.rb
@@ -2,14 +2,18 @@
require 'action_controller/metal/renderers'
require 'action_controller/metal/responder'
-require 'to_spreadsheet/axlsx/renderer'
+require 'to_spreadsheet/renderer'
# This will let us do thing like `render :xlsx => 'index'`
# This is similar to how Rails internally implements its :json and :xml renderers
ActionController::Renderers.add :xlsx do |template, options|
filename = options[:filename] || options[:template] || 'data'
- html = with_context ToSpreadsheet.context.derive do
+ html = with_context ToSpreadsheet::Context.global.merge(ToSpreadsheet::Context.new) do
+ # local context
+ @local_formats.each do |selector, &block|
+ context.process_dsl selector, &block
+ end if @local_formats
render_to_string(options[:template], options)
end
View
86 lib/to_spreadsheet/axlsx/formatter.rb
@@ -1,86 +0,0 @@
-module ToSpreadsheet
- module Axlsx
- module Formatter
- COL_INFO_PROPS = %w(bestFit collapsed customWidth hidden phonetic width).map(&:to_sym)
-
- def apply_formats(package, context)
- package.workbook.worksheets.each do |sheet|
- fmt = context.formats(sheet)
- fmt.workbook_props.each do |prop, value|
- package.send(:"#{prop}=", value)
- end
- fmt.sheet_props.each do |set, props|
- apply_props sheet.send(set), props, context
- end
- fmt.column_props.each do |v|
- idx, props = v[0], v[1]
- apply_props sheet.column_info[0], props.slice(*COL_INFO_PROPS), context
- props = props.except(*COL_INFO_PROPS)
- sheet.col_style idx, props if props.present?
- end
- fmt.row_props.each do |v|
- idx, props = v[0], v[1]
- sheet.row_style idx, props
- end
- fmt.range_props.each do |v|
- range, props = v[0], v[1]
- apply_props sheet[range], props, context
- end
- fmt.css_props.each do |v|
- css_sel, props = v[0], v[1]
- context.node_from_entity(sheet).css(css_sel).each do |node|
- apply_props context.entity_from_node(node), props, context
- end
- end
- end
- end
-
- private
- def apply_props(obj, props, context)
- if props.is_a?(Proc)
- context.instance_exec(obj, &props)
- return
- end
-
- props = props.dup
- props.each do |k, v|
- props[k] = context.instance_exec(obj, &v) if v.is_a?(Proc)
- end
-
- props.each do |k, v|
- next if v.nil?
- if k == :default_value
- unless obj.value.present? && !([:integer, :float].include?(obj.type) && obj.value.zero?)
- obj.type = cell_type_from_value(v)
- obj.value = v
- end
- else
- setter = :"#{k}="
- obj.send setter, v if obj.respond_to?(setter)
- if obj.respond_to?(:cells)
- obj.cells.each do |cell|
- cell.send setter, v if cell.respond_to?(setter)
- end
- end
- end
- end
- end
-
- def cell_type_from_value(v)
- if v.is_a?(Date)
- :date
- elsif v.is_a?(Time)
- :time
- elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
- :boolean
- elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric
- :integer
- elsif v.to_s.match(/\A[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\Z/) #float
- :float
- else
- :string
- end
- end
- end
- end
-end
View
52 lib/to_spreadsheet/axlsx/renderer.rb
@@ -1,52 +0,0 @@
-require 'axlsx'
-require 'to_spreadsheet/axlsx/formatter'
-module ToSpreadsheet
- module Axlsx
- module Renderer
- include Formatter
- extend self
-
- def to_stream(html, context = ToSpreadsheet.context)
- to_package(html, context).to_stream
- end
-
- def to_data(html, context = ToSpreadsheet.context)
- to_package(html, context).to_stream.read
- end
-
- def to_package(html, context = ToSpreadsheet.context)
- package = build_package(html, context)
- apply_formats(package, context)
- # Don't leak memory: clear all dom <-> axslsx associations
- context.clear_assoc!
- # Numbers compat
- package.use_shared_strings = true
- package
- end
-
- private
-
- def build_package(html, context)
- package = ::Axlsx::Package.new
- spreadsheet = package.workbook
- doc = Nokogiri::HTML::Document.parse(html)
- context.assoc! spreadsheet, doc
- doc.css('table').each_with_index do |xml_table, i|
- sheet = spreadsheet.add_worksheet(
- name: xml_table.css('caption').inner_text.presence || xml_table['name'] || "Sheet #{i + 1}"
- )
- context.assoc! sheet, xml_table
- xml_table.css('tr').each do |row_node|
- xls_row = sheet.add_row
- context.assoc! xls_row, row_node
- row_node.css('th,td').each do |cell_node|
- xls_col = xls_row.add_cell cell_node.inner_text
- context.assoc! xls_col, cell_node
- end
- end
- end
- package
- end
- end
- end
-end
View
153 lib/to_spreadsheet/context.rb
@@ -1,134 +1,115 @@
require 'to_spreadsheet/context/pairing'
-require 'to_spreadsheet/formats'
+require 'to_spreadsheet/rule'
+require 'to_spreadsheet/rule/base'
+require 'to_spreadsheet/rule/container'
+require 'to_spreadsheet/rule/format'
+require 'to_spreadsheet/rule/default_value'
+require 'to_spreadsheet/rule/sheet'
+require 'to_spreadsheet/rule/workbook'
module ToSpreadsheet
# This is the DSL context for `format_xls`
# It maintains the current formats set to enable for local and nested `format_xls` blocks
class Context
- # todo (cleaner code): split features further into modules
- # todo (extensibility): add processing callbacks (internal API)
include Pairing
+ attr_accessor :rules
- def initialize(wb_options = nil)
- @formats = []
- @current_format = Formats.new
- workbook wb_options if wb_options
- end
-
- # Returns a new formats jar for a given sheet
- def formats(sheet)
- format = Formats.new
- @formats.each do |v|
- sel, fmt = v[0], v[1]
- format.merge!(fmt) if selects?(sel, sheet)
+ class << self
+ def global
+ @global ||= new
end
- format
end
- # Check if selector matches a given sheet / cell / row
- def selects?(selector, entity)
- return true if !selector
- type, val = selector[0], selector[1]
- sheet = entity.is_a?(::Axlsx::Workbook) ? entity : (entity.respond_to?(:workbook) ? entity.workbook : entity.worksheet.workbook)
- doc = node_from_entity(sheet)
- case type
- when :css
- doc.css(val).include?(node_from_entity(entity))
- when :column
- return false if entity.is_a?(Axlsx::Row)
- entity.index == val if entity.is_a?(Axlsx::Cell)
- when :row
- return entity.index == val if entity.is_a?(Axlsx::Row)
- entity.row.index == val if entity.is_a?(Axlsx::Cell)
- when :range
- if entity.is_a?(Axlsx::Cell)
- pos = entity.pos
- top_left, bot_right = val.split(':').map { |s| Axlsx.name_to_indices(s) }
- pos[0] >= top_left[0] && pos[0] <= bot_right[0] && pos[1] >= top_left[1] && pos[1] <= bot_right[1]
- end
- end
+ def initialize(wb_options = nil)
+ @rules = []
+ workbook wb_options if wb_options
end
- # current format, used internally
- attr_accessor :current_format
-
- # format_xls 'table.zebra' do
- # format 'td', lambda { |cell| {b: true} if cell.row.even? }
- # end
+ # Examples:
+ # format_xls 'table.zebra' do
+ # format 'td', lambda { |cell| {b: true} if cell.row.even? }
+ # end
+ # format_xls ToSpreadsheet.theme(:a_theme)
+ # format_xls 'table.zebra', ToSpreadsheet.theme(:zebra)
def format_xls(selector = nil, theme = nil, &block)
selector, theme = nil, selector if selector.is_a?(Proc) && !theme
- add_format(selector, &theme) if theme
- add_format(selector, &block) if block
+ process_dsl(selector, &theme) if theme
+ process_dsl(selector, &block) if block
self
end
+ def process_dsl(selector, &block)
+ @rule_container = add_rule :container, *selector_query(selector)
+ instance_eval(&block)
+ @rule_container = nil
+ end
+
+ def workbook(selector = nil, value)
+ add_rule :workbook, *selector_query(selector), value
+ end
+
# format 'td.b', b: true # bold
# format column: 0, width: 50
# format 'A1:C30', b: true
# Accepted properties: http://rubydoc.info/github/randym/axlsx/Axlsx/Cell
# column format also accepts Axlsx columnInfo settings
def format(selector = nil, options)
options = options.dup
- selector = extract_selector!(selector, options)
- add selector[0], selector, options
+ selector = selector_query(selector, options)
+ add_rule :format, *selector, options
end
# sheet 'table.landscape', page_setup: { orientation: landscape }
def sheet(selector = nil, options)
options = options.dup
- selector = extract_selector!(selector, options)
- add :sheet, selector, options
+ selector = selector_query(selector, options)
+ add_rule :sheet, *selector, options
end
# default 'td.c', 5
def default(selector, value)
- options = {default_value: value}
- selector = extract_selector!(selector, options)
- add selector[0], selector, options
- end
-
- def add(setting, selector, value)
- @current_format[setting] << [selector.try(:[], 1), value] if selector || value
- end
-
- def workbook(selector = nil, value)
- add :package, selector, value
+ selector = selector_query(selector)
+ add_rule :default_value, *selector, value
end
- def apply(theme = nil, &block)
- add_format &theme if theme
- add_format &block if block
- self
+ def add_rule(rule_type, selector_type, selector_value, options = {})
+ rule = ToSpreadsheet::Rule.make(rule_type, selector_type, selector_value, options)
+ if @rule_container
+ @rule_container.children << rule
+ else
+ @rules << rule
+ end
+ rule
end
- def derive
- derived = dup
- derived.current_format = derived.current_format.derive
- derived
+ # A new context
+ def merge(other_context)
+ ctx = Context.new()
+ ctx.rules = rules + other_context.rules
+ ctx
end
private
- def add_format(sheet_sel = nil, &block)
- format_was = @current_format
- @current_format = @current_format.derive
- instance_eval &block
- @formats << [extract_selector!(sheet_sel), @current_format]
- @current_format = format_was
- end
-
- def extract_selector!(selector, options = {})
- if selector
- if selector =~ /:/ && selector[0].upcase == selector[0]
- return [:range, selector]
+ # Extract selector query from DSL arguments
+ #
+ # Figures out text type:
+ # selector_query('td.num') # [:css, "td.num"]
+ # selector_query('A0:B5') # [:range, "A0:B5"]
+ #
+ # If text is nil, extracts first of row, range, and css keys
+ # selector_query(nil, {column: 0}] # [:column, 0]
+ def selector_query(text, opts = {})
+ if text
+ if text =~ /:/ && text[0].upcase == text[0]
+ return [:range, text]
else
- return [:css, selector]
+ return [:css, text]
end
end
- [:column, :row, :range].each do |key|
- return [key, options.delete(key)] if options.key?(key)
- end
- selector
+ key = [:column, :row, :range].detect { |key| opts.key?(key) }
+ return [key, opts.delete(key)] if key
+ [nil, nil]
end
end
end
View
8 lib/to_spreadsheet/context/pairing.rb
@@ -9,14 +9,18 @@ def assoc!(entity, node)
@node_to_entity[node] = entity
end
- def entity_from_node(node)
+ def to_xls_entity(node)
@node_to_entity[node]
end
- def node_from_entity(entity)
+ def to_xml_node(entity)
@entity_to_node[entity]
end
+ def xml_node_and_xls_entity(entity)
+ [@entity_to_node[entity], entity, @node_to_entity[entity]].compact
+ end
+
def clear_assoc!
@entity_to_node = {}
@node_to_entity = {}
View
59 lib/to_spreadsheet/formats.rb
@@ -1,59 +0,0 @@
-module ToSpreadsheet
- # An intrnal container of formats
- class Formats
- attr_accessor :styles_by_type
- attr_writer :sheet_props
-
- # A list of [format_selector, formatting block] by `type`
- # `type` is one of :sheet, :workbook, :range, :column, :row, :css
- def [](type)
- (@styles_by_type ||= {})[type.to_sym] ||= []
- end
-
- def each
- @styles_by_type.each do |k, v|
- yield(k, v)
- end if @styles_by_type
- end
-
- # A list of all formatting blocks with type :sheet
- def sheet_props
- self[:sheet].map(&:last).inject({}, &:merge)
- end
-
- # Workbook props without selectors
- def workbook_props
- self[:workbook].map(&:last).inject({}, &:merge)
- end
-
- def range_props
- self[:range]
- end
-
- def column_props
- self[:column]
- end
-
- def row_props
- self[:row]
- end
-
- def css_props
- self[:css]
- end
-
- def derive
- derived = Formats.new
- each { |type, styles| derived[type].concat(styles) }
- derived
- end
-
- def merge!(other_fmt)
- other_fmt.each { |type, styles| self[type].concat(styles) }
- end
-
- def inspect
- "Formats(sheet: #@sheet_props, styles: #@styles_by_type)"
- end
- end
-end
View
7 lib/to_spreadsheet/helpers.rb
@@ -1,16 +1,11 @@
module ToSpreadsheet
module Helpers
-
- def to_spreadsheet(selector, &block)
- context.apply(block)
- end
-
def format_xls(selector = nil, &block)
context.format_xls selector, &block
end
def context
- @context || ToSpreadsheet.context
+ @context || ToSpreadsheet::Context.global
end
def with_context(context, &block)
View
58 lib/to_spreadsheet/renderer.rb
@@ -0,0 +1,58 @@
+require 'axlsx'
+module ToSpreadsheet
+ module Renderer
+ extend self
+
+ def to_stream(html, local_context = nil)
+ to_package(html, local_context).to_stream
+ end
+
+ def to_data(html, local_context = nil)
+ to_package(html, local_context).to_stream.read
+ end
+
+ def to_package(html, local_context = nil)
+ with_context init_context(local_context) do
+ package = build_package(html, context)
+ context.rules.each do |rule|
+ puts "Applying #{rule}"
+ rule.apply(context, package)
+ end
+ package
+ end
+ end
+
+ private
+
+ def init_context(local_context)
+ local_context ||= ToSpreadsheet::Context.new
+ ToSpreadsheet::Context.global.merge local_context
+ end
+
+ def build_package(html, context)
+ package = ::Axlsx::Package.new
+ spreadsheet = package.workbook
+ doc = Nokogiri::HTML::Document.parse(html)
+ # Workbook <-> %document association
+ context.assoc! spreadsheet, doc
+ doc.css('table').each_with_index do |xml_table, i|
+ sheet = spreadsheet.add_worksheet(
+ name: xml_table.css('caption').inner_text.presence || xml_table['name'] || "Sheet #{i + 1}"
+ )
+ # Sheet <-> %table association
+ context.assoc! sheet, xml_table
+ xml_table.css('tr').each do |row_node|
+ xls_row = sheet.add_row
+ # Row <-> %tr association
+ context.assoc! xls_row, row_node
+ row_node.css('th,td').each do |cell_node|
+ xls_col = xls_row.add_cell cell_node.inner_text
+ # Cell <-> th or td association
+ context.assoc! xls_col, cell_node
+ end
+ end
+ end
+ package
+ end
+ end
+end
View
9 lib/to_spreadsheet/rule.rb
@@ -0,0 +1,9 @@
+require 'active_support/core_ext'
+module ToSpreadsheet
+ module Rule
+ def self.make(rule_type, selector_type, selector_value, options)
+ klass = "ToSpreadsheet::Rule::#{rule_type.to_s.camelize}".constantize
+ klass.new(selector_type, selector_value, options)
+ end
+ end
+end
View
38 lib/to_spreadsheet/rule/base.rb
@@ -0,0 +1,38 @@
+require 'to_spreadsheet/selectors'
+module ToSpreadsheet
+ module Rule
+ class Base
+ include ::ToSpreadsheet::Selectors
+ attr_reader :selector_type, :selector_query, :options
+
+ def initialize(selector_type, selector_query, options)
+ @selector_type = selector_type
+ @selector_query = selector_query
+ @options = options
+ end
+
+ def applies_to?(context, xml_or_xls_node)
+ return true if !selector_type
+ node, entity = context.xml_node_and_xls_entity(xml_or_xls_node)
+ sheet = entity.is_a?(::Axlsx::Workbook) ? entity : (entity.respond_to?(:workbook) ? entity.workbook : entity.worksheet.workbook)
+ doc = context.to_xml_node(sheet)
+ query_match?(
+ selector_type: selector_type,
+ selector_query: selector_query,
+ xml_document: doc,
+ xml_node: node,
+ xls_worksheet: sheet,
+ xls_entity: entity
+ )
+ end
+
+ def type
+ self.class.name.demodulize.underscore.to_sym
+ end
+
+ def to_s
+ "Rule [#{type}, #{selector_type}, #{selector_query}, #{options}"
+ end
+ end
+ end
+end
View
25 lib/to_spreadsheet/rule/container.rb
@@ -0,0 +1,25 @@
+module ToSpreadsheet
+ module Rule
+ # Applies children rules to all the matching tables
+ class Container < Base
+ attr_reader :children
+ def initialize(*args)
+ super
+ @children = []
+ end
+
+ def apply(context, package)
+ package.workbook.worksheets.each do |sheet|
+ table = context.to_xml_node(sheet)
+ if applies_to?(context, table)
+ children.each { |c| c.apply(context, sheet) }
+ end
+ end
+ end
+
+ def to_s
+ "Rules(#{selector_type}, #{selector_query}) [#{children.map(&:to_s)}]"
+ end
+ end
+ end
+end
View
19 lib/to_spreadsheet/rule/default_value.rb
@@ -0,0 +1,19 @@
+require 'to_spreadsheet/type_from_value'
+module ToSpreadsheet
+ module Rule
+ class DefaultValue < Base
+ include ::ToSpreadsheet::TypeFromValue
+
+ def apply(context, sheet)
+ default = options
+ each_cell context, sheet, selector_type, selector_query do |cell|
+ unless cell.value.present? &&
+ !([:integer, :float].include?(cell.type) && cell.value.zero?)
+ cell.type = cell_type_from_value(default)
+ cell.value = default
+ end
+ end
+ end
+ end
+ end
+end
View
64 lib/to_spreadsheet/rule/format.rb
@@ -0,0 +1,64 @@
+require 'to_spreadsheet/type_from_value'
+require 'set'
+module ToSpreadsheet
+ module Rule
+ class Format < Base
+ include ::ToSpreadsheet::TypeFromValue
+ def apply(context, sheet)
+ case selector_type
+ when :css
+ css_match selector_query, context.to_xml_node(sheet) do |xml_node|
+ apply_inline_styles context, context.to_xls_entity(xml_node)
+ end
+ when :row
+ sheet.row_style selector_query, options if options.present?
+ when :column
+ inline_styles = options.except(*COL_INFO_PROPS)
+ sheet.col_style selector_query, inline_styles if inline_styles.present?
+ apply_col_info sheet.column_info[selector_query]
+ when :range
+ apply_inline_styles range_match(selector_type, sheet), context
+ end
+ end
+
+ private
+ COL_INFO_PROPS = %w(bestFit collapsed customWidth hidden phonetic width).map(&:to_sym).to_set
+ def apply_col_info(col_info)
+ return if col_info.nil?
+ options.each do |k, v|
+ if COL_INFO_PROPS.include?(k)
+ col_info.send :"#{k}=", v
+ end
+ end
+ end
+
+ def apply_inline_styles(context, xls_ent)
+ # Custom format rule
+ # format 'td.sel', lambda { |node| ...}
+ if self.options.is_a?(Proc)
+ context.instance_exec(xls_ent, &self.options)
+ return
+ end
+
+ options = self.options.dup
+ # Compute Proc rules
+ # format 'td.sel', color: lambda {|node| ...}
+ options.each do |k, v|
+ options[k] = context.instance_exec(xls_ent, &v) if v.is_a?(Proc)
+ end
+
+ # Apply inline styles
+ options.each do |k, v|
+ next if v.nil?
+ setter = :"#{k}="
+ xls_ent.send setter, v if xls_ent.respond_to?(setter)
+ if xls_ent.respond_to?(:cells)
+ xls_ent.cells.each do |cell|
+ cell.send setter, v if cell.respond_to?(setter)
+ end
+ end
+ end
+ end
+ end
+ end
+end
View
18 lib/to_spreadsheet/rule/sheet.rb
@@ -0,0 +1,18 @@
+module ToSpreadsheet
+ module Rule
+ class Sheet < Base
+ def apply(context, sheet)
+ options.each { |k, v|
+ if v.is_a?(Hash)
+ sub = sheet.send(k)
+ v.each do |sub_k, sub_v|
+ sub.send :"#{sub_k}=", sub_v
+ end
+ else
+ sheet.send :"#{k}=", v
+ end
+ }
+ end
+ end
+ end
+end
View
10 lib/to_spreadsheet/rule/workbook.rb
@@ -0,0 +1,10 @@
+module ToSpreadsheet
+ module Rule
+ class Workbook < Base
+ def apply(context, sheet)
+ workbook = sheet.workbook
+ options.each { |k, v| workbook.send :"#{k}=", v }
+ end
+ end
+ end
+end
View
89 lib/to_spreadsheet/selectors.rb
@@ -0,0 +1,89 @@
+module ToSpreadsheet
+ # This is the DSL context for `format_xls`
+ # Query types: :css, :column, :row or :range
+ # Query values:
+ # For css: [String] css selector
+ # For column and row: [Fixnum] column/row number
+ # For range: [String] table range, e.g. A4:B5
+ module Selectors
+ # Flexible API query match
+ # Options (all optional):
+ # xls_worksheet
+ # xls_entity
+ # xml_document
+ # xml_node
+ # selector_type :css, :column, :row or :range
+ # selector_query
+ def query_match?(options)
+ return true if !options[:selector_query]
+ case options[:selector_type]
+ when :css
+ css_match? options[:selector_query], options[:xml_document], options[:xml_node]
+ when :column
+ return false unless [Axlsx::Row, Axlsx::Cell].include?(options[:xml_node].class)
+ column_number_match? options[:selector_query], options[:xml_node]
+ when :row
+ return false unless Axlsx::Cell == options[:xml_node].class
+ row_number_match? options[:selector_query], options[:xml_node]
+ when :range
+ return false if entity.is_a?(Axlsx::Cell)
+ range_contains? options[:selector_query], options[:xml_node]
+ else
+ raise "Unsupported type #{options[:selector_type].inspect} (:css, :column, :row or :range expected)"
+ end
+ end
+
+ def each_cell(context, sheet, selector_type, selector_query, &block)
+ if !selector_type
+ sheet.rows.each do |row|
+ sheet.cells.each do |cell|
+ block.(cell)
+ end
+ end
+ return
+ end
+ case selector_type
+ when :css
+ css_match selector_query, context.to_xml_node(sheet) do |xml_node|
+ block.(context.to_xls_entity(xml_node))
+ end
+ when :column
+ sheet.cols[selector_query].cells.each(&block)
+ when :row
+ sheet.cols[selector_query].cells.each(&block)
+ when :range
+ sheet[range].each(&block)
+ end
+ end
+
+ def css_match(css_selector, xml_node, &block)
+ xml_node.css(css_selector).each(&block)
+ end
+
+ def css_match?(css_selector, xml_document, xml_node)
+ xml_document.css(css_selector).include?(xml_node)
+ end
+
+ def row_number_match?(row_number, xls_row_or_cell)
+ if xls_row_or_cell.is_a? Axlsx::Row
+ row_number == xls_row_or_cell.index
+ elsif xls_row_or_cell.is_a? Axlsx::Cell
+ row_number == xls_row_or_cell.row.index
+ end
+ end
+
+ def column_number_match?(column_number, xls_cell)
+ xls_cell.index == column_number if xls_cell.is_a?(Axlsx::Cell)
+ end
+
+ def range_match(range, xls_sheet)
+ xls_sheet[range]
+ end
+
+ def range_contains?(range, xls_cell)
+ pos = xls_cell.pos
+ top_left, bot_right = range.split(':').map { |s| Axlsx.name_to_indices(s) }
+ pos[0] >= top_left[0] && pos[0] <= bot_right[0] && pos[1] >= top_left[1] && pos[1] <= bot_right[1]
+ end
+ end
+end
View
5 lib/to_spreadsheet/themes/default.rb
@@ -1,7 +1,8 @@
module ToSpreadsheet::Themes
module Default
::ToSpreadsheet.theme :default do
- workbook use_autowidth: true
+ workbook use_autowidth: true,
+ use_shared_strings: true
sheet page_setup: {
fit_to_height: 1,
fit_to_width: 1,
@@ -10,7 +11,7 @@ module Default
# Set value type based on CSS class
format 'td,th', lambda { |cell|
val = cell.value
- case node_from_entity(cell)[:class]
+ case to_xml_node(cell)[:class]
when /decimal|float/
cell.type = :float
when /num|int/
View
19 lib/to_spreadsheet/type_from_value.rb
@@ -0,0 +1,19 @@
+module ToSpreadsheet
+ module TypeFromValue
+ def cell_type_from_value(v)
+ if v.is_a?(Date)
+ :date
+ elsif v.is_a?(Time)
+ :time
+ elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
+ :boolean
+ elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric
+ :integer
+ elsif v.to_s.match(/\A[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\Z/) #float
+ :float
+ else
+ :string
+ end
+ end
+ end
+end
View
0 lib/to_spreadsheet/xlsx.rb
No changes.
View
2 spec/defaults_spec.rb
@@ -2,7 +2,7 @@
-describe ToSpreadsheet::Axlsx::Formatter do
+describe ToSpreadsheet::Rule::DefaultValue do
let :spreadsheet do
build_spreadsheet(haml: <<HAML)
- format_xls 'table' do
View
2 spec/format_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ToSpreadsheet::Axlsx::Formatter do
+describe ToSpreadsheet::Rule::Format do
let :spreadsheet do
build_spreadsheet haml: <<-HAML
:ruby
View
2 spec/spec_helper.rb
@@ -14,5 +14,5 @@ def build_spreadsheet(src = {})
elsif src[:file]
File.read(File.expand_path "support/#{src[:file]}", File.dirname(__FILE__))
end
- ToSpreadsheet::Axlsx::Renderer.to_package(Haml::Engine.new(haml).render)
+ ToSpreadsheet::Renderer.to_package(Haml::Engine.new(haml).render)
end
View
2 spec/worksheets_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ToSpreadsheet::Axlsx::Renderer do
+describe ToSpreadsheet::Renderer do
let :spreadsheet do
build_spreadsheet haml: <<-HAML
%table

0 comments on commit 6e00449

Please sign in to comment.