@@ -37,6 +37,7 @@ def self.from_spreadsheet(spreadsheet, options = {})
3737 end
3838
3939 data_sources = add_data_sources ( workbook , header_format , options )
40+ pp data_sources
4041 add_worksheet_validation ( workbook , worksheet , column_indexes , data_sources , header_format , options )
4142
4243 workbook . worksheets . each do |ws |
@@ -47,6 +48,10 @@ def self.from_spreadsheet(spreadsheet, options = {})
4748 io . string
4849 end
4950
51+ def self . sanitize_defined_name ( raw )
52+ raw . gsub ( /^[A-Za-z_]/ , "_" )
53+ end
54+
5055 def self . add_data_sources ( workbook , header_format , options = { } )
5156 data_sources = options . fetch ( "data_sources" , { } ) || { }
5257 return { } if data_sources . empty?
@@ -57,8 +62,19 @@ def self.add_data_sources(workbook, header_format, options = {})
5762
5863 data_source_refs = { }
5964
60- data_sources . each_with_index do |( data_key , data_values ) , column_index |
61- data_source_refs [ data_key ] = add_data_source ( workbook , data_sheet , data_key , data_values , column_index , header_format )
65+ column_index = 0
66+ data_sources . each do |data_key , data_values |
67+ if data_values . is_a? ( Hash )
68+ # nested, conditional data structure
69+ data_values . each do |data_value , sub_values |
70+ sub_key = sanitize_defined_name ( "#{ data_key } _#{ data_value } " )
71+ data_source_refs [ sub_key ] = add_data_source ( workbook , data_sheet , sub_key , sub_values , column_index , header_format )
72+ column_index += 1
73+ end
74+ else
75+ data_source_refs [ data_key ] = add_data_source ( workbook , data_sheet , data_key , data_values , column_index , header_format )
76+ column_index += 1
77+ end
6278 end
6379
6480 data_source_refs
@@ -68,15 +84,18 @@ def self.add_data_sources(workbook, header_format, options = {})
6884 #
6985 # Returnd the named range's name
7086 def self . add_data_source ( workbook , data_sheet , data_key , data_values , column_index , header_format )
71- raise ArgumentError unless data_values . is_a? ( Array )
87+ unless data_values . is_a? ( Array )
88+ debugger
89+ raise ArgumentError , "data_values should be an array (got #{ data_values . inspect } "
90+ end
7291
7392 data_start = xl_rowcol_to_cell ( 1 , column_index , true , true )
7493 data_end = xl_rowcol_to_cell ( data_values . length , column_index , true , true )
7594
7695 defined_name_source = "=#{ DATA_WORKSHEET_NAME } !#{ data_start } :#{ data_end } "
7796
7897 data_sheet . write ( 0 , column_index , data_key , header_format )
79- data_sheet . write_col ( 1 , column_index , data_values )
98+ data_sheet . write_col ( 1 , column_index , data_values . map ( & :strip ) )
8099 defined_name = data_key
81100 workbook . define_name ( defined_name , defined_name_source )
82101 defined_name
@@ -85,6 +104,7 @@ def self.add_data_source(workbook, data_sheet, data_key, data_values, column_ind
85104 # TODO: we should DRY this up with the Spreadsheet.from_objects logic
86105 def self . rewrite_validation_column_names ( column_validations , options )
87106 return column_validations unless options [ "humanize_headers_class" ]
107+
88108 klass = options [ "humanize_headers_class" ]
89109
90110 column_validations . each_with_object ( { } ) do |( attribute , v ) , obj |
@@ -109,18 +129,34 @@ def self.add_worksheet_validation(workbook, worksheet, column_indexes, data_sour
109129 next
110130 end
111131
112- defined_name = data_sources [ column_validation . data_source ]
113- raise ArgumentError , "missing data for data_source=#{ column_validation . data_source } " unless defined_name
114-
115- validation_options = add_column_validation ( column_validation , defined_name )
116-
117- pp validation_options
118-
119- worksheet . data_validation ( 1 , column_index , ROW_MAX , column_index , validation_options )
132+ # Excel's `INDIRECT` function lets us build up the name of a defined range dynamically
133+ if column_validation . indirect_built_from
134+ parent_column_index = column_indexes [ column_validation . indirect_built_from ]
135+
136+ ( 1 ..100 ) . each do |row_index |
137+ indirect_cell = xl_rowcol_to_cell ( row_index , parent_column_index , false , false )
138+ defined_name = "INDIRECT(\" #{ column_validation . data_source } \" & \" _\" & SUBSTITUTE(#{ indirect_cell } , \" \" , \" \" ))"
139+
140+ validation_options = generate_validation ( column_validation , defined_name )
141+ pp validation_options
142+ worksheet . data_validation ( row_index , column_index , validation_options )
143+ end
144+ else
145+ defined_name = data_sources [ column_validation . data_source ]
146+ unless defined_name
147+ raise ArgumentError , "missing data for data_source=#{ column_validation . data_source } "
148+ end
149+
150+ validation_options = generate_validation ( column_validation , defined_name )
151+ pp validation_options
152+ worksheet . data_validation ( 1 , column_index , ROW_MAX , column_index , validation_options )
153+ end
154+ rescue StandardError => e
155+ debugger
120156 end
121157 end
122158
123- def self . add_column_validation ( column_validation , defined_name )
159+ def self . generate_validation ( column_validation , defined_name )
124160 {
125161 "validate" => "list" ,
126162 "input_title" => "Select a value" ,
0 commit comments