discerner 1.1.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +97 -0
  4. data/Rakefile +29 -0
  5. data/app/assets/images/discerner/add.png +0 -0
  6. data/app/assets/images/discerner/ajax-loader.gif +0 -0
  7. data/app/assets/images/discerner/bar.gif +0 -0
  8. data/app/assets/images/discerner/bullet_arrow_down.png +0 -0
  9. data/app/assets/images/discerner/bullet_arrow_up.png +0 -0
  10. data/app/assets/images/discerner/cog.png +0 -0
  11. data/app/assets/images/discerner/delete.png +0 -0
  12. data/app/assets/images/discerner/edit.png +0 -0
  13. data/app/assets/images/discerner/excel.png +0 -0
  14. data/app/assets/images/discerner/greencheck.gif +0 -0
  15. data/app/assets/images/discerner/rails.png +0 -0
  16. data/app/assets/images/discerner/show.png +0 -0
  17. data/app/assets/images/discerner/switch_minus.gif +0 -0
  18. data/app/assets/images/discerner/switch_plus.gif +0 -0
  19. data/app/assets/javascripts/discerner/application.js +20 -0
  20. data/app/assets/javascripts/discerner/combobox.js +301 -0
  21. data/app/assets/javascripts/discerner/discerner.js +19 -0
  22. data/app/assets/javascripts/discerner/export_parameters.js +13 -0
  23. data/app/assets/javascripts/discerner/jquery/jquery.blockUI.js +576 -0
  24. data/app/assets/javascripts/discerner/jquery/jquery.form.js +1074 -0
  25. data/app/assets/javascripts/discerner/nested_attributes.js +69 -0
  26. data/app/assets/javascripts/discerner/search_combinations.js +49 -0
  27. data/app/assets/javascripts/discerner/search_parameter.js +131 -0
  28. data/app/assets/javascripts/discerner/search_parameter_value.js +172 -0
  29. data/app/assets/javascripts/discerner/searches.js +93 -0
  30. data/app/assets/javascripts/discerner/url.js +42 -0
  31. data/app/assets/stylesheets/discerner/application.css +16 -0
  32. data/app/assets/stylesheets/discerner/buttons.sass +13 -0
  33. data/app/assets/stylesheets/discerner/categorized_autocompleter.sass +53 -0
  34. data/app/assets/stylesheets/discerner/discerner.sass +51 -0
  35. data/app/assets/stylesheets/discerner/export_parameters.sass +43 -0
  36. data/app/assets/stylesheets/discerner/links.sass +29 -0
  37. data/app/assets/stylesheets/discerner/searches.sass +205 -0
  38. data/app/assets/stylesheets/discerner/tables.sass +32 -0
  39. data/app/controllers/discerner/application_controller.rb +2 -0
  40. data/app/controllers/discerner/export_parameters_controller.rb +5 -0
  41. data/app/controllers/discerner/parameters_controller.rb +5 -0
  42. data/app/controllers/discerner/searches_controller.rb +5 -0
  43. data/app/helpers/discerner/application_helper.rb +4 -0
  44. data/app/helpers/discerner/parameters_helper.rb +5 -0
  45. data/app/helpers/discerner/searches_helper.rb +5 -0
  46. data/app/models/discerner/dictionary.rb +5 -0
  47. data/app/models/discerner/export_parameter.rb +5 -0
  48. data/app/models/discerner/operator.rb +5 -0
  49. data/app/models/discerner/parameter.rb +5 -0
  50. data/app/models/discerner/parameter_category.rb +5 -0
  51. data/app/models/discerner/parameter_type.rb +5 -0
  52. data/app/models/discerner/parameter_value.rb +5 -0
  53. data/app/models/discerner/parameter_value_categorization.rb +5 -0
  54. data/app/models/discerner/parameter_value_category.rb +5 -0
  55. data/app/models/discerner/search.rb +5 -0
  56. data/app/models/discerner/search_combination.rb +5 -0
  57. data/app/models/discerner/search_parameter.rb +5 -0
  58. data/app/models/discerner/search_parameter_value.rb +5 -0
  59. data/app/views/discerner/export_parameters/index.html.haml +55 -0
  60. data/app/views/discerner/parameters/_values_autocompleter.html.haml +49 -0
  61. data/app/views/discerner/parameters/values.html.haml +1 -0
  62. data/app/views/discerner/searches/_form.html.haml +21 -0
  63. data/app/views/discerner/searches/_form_combined_searches.html.haml +32 -0
  64. data/app/views/discerner/searches/_form_controls.html.haml +8 -0
  65. data/app/views/discerner/searches/_form_header.html.haml +39 -0
  66. data/app/views/discerner/searches/_form_search_parameters.html.haml +28 -0
  67. data/app/views/discerner/searches/_list.html.haml +17 -0
  68. data/app/views/discerner/searches/_search_combination_fields.html.haml +22 -0
  69. data/app/views/discerner/searches/_search_parameter_fields.html.haml +48 -0
  70. data/app/views/discerner/searches/_search_parameter_value_fields.html.haml +62 -0
  71. data/app/views/discerner/searches/_summary.html.haml +25 -0
  72. data/app/views/discerner/searches/edit.html.haml +8 -0
  73. data/app/views/discerner/searches/index.html.haml +13 -0
  74. data/app/views/discerner/searches/index.js.haml +1 -0
  75. data/app/views/discerner/searches/new.html.haml +3 -0
  76. data/app/views/discerner/searches/rename.html.haml +6 -0
  77. data/app/views/discerner/searches/update.js.haml +7 -0
  78. data/app/views/discerner/shared/_categorized_autocompleter_items.html.haml +15 -0
  79. data/app/views/discerner/shared/_error_messages.html.haml +5 -0
  80. data/app/views/layouts/discerner/searches.html.erb +17 -0
  81. data/config/cucumber.yml +8 -0
  82. data/config/routes.rb +17 -0
  83. data/db/migrate/20121004040716_create_discerner_dictionaries.rb +11 -0
  84. data/db/migrate/20121004153043_create_discerner_parameter_categories.rb +12 -0
  85. data/db/migrate/20121005194843_create_discerner_parameter_types.rb +11 -0
  86. data/db/migrate/20121005203223_create_discerner_parameters.rb +14 -0
  87. data/db/migrate/20121008154855_create_discerner_operators.rb +13 -0
  88. data/db/migrate/20121008160313_create_discerner_operators_parameter_types.rb +8 -0
  89. data/db/migrate/20121008161455_create_discerner_parameter_values.rb +13 -0
  90. data/db/migrate/20121008180829_create_discerner_searches.rb +11 -0
  91. data/db/migrate/20121008182443_create_discerner_search_parameters.rb +11 -0
  92. data/db/migrate/20121011205130_create_discerner_search_parameter_values.rb +15 -0
  93. data/db/migrate/20121211213215_add_dictionary_id_to_discerner_searches.rb +5 -0
  94. data/db/migrate/20130205193602_create_discerner_search_combinations.rb +12 -0
  95. data/db/migrate/20130211230636_create_discerner_export_parameters.rb +9 -0
  96. data/db/migrate/20130213185818_add_search_columns_to_discerner_parameters.rb +38 -0
  97. data/db/migrate/20130213205255_rename_database_name_to_search_value_in_discerner_parameter_values.rb +5 -0
  98. data/db/migrate/20130215165416_add_searchable_to_discerner_parameters.rb +5 -0
  99. data/db/migrate/20130218230257_add_exclusive_to_discerner_parameters.rb +5 -0
  100. data/db/migrate/20130220163015_replace_integer_type_with_numeric.rb +22 -0
  101. data/db/migrate/20130221172826_add_unique_identifier_to_discerner_parameters.rb +5 -0
  102. data/db/migrate/20130222052924_change_search_attribute_to_method.rb +29 -0
  103. data/db/migrate/20130222070959_add_export_columns_to_discerner_parameters.rb +6 -0
  104. data/db/migrate/20130227031747_add_unique_identifier_to_discerner_operators.rb +16 -0
  105. data/db/migrate/20130306015019_change_discerner_parameter_values_name.rb +9 -0
  106. data/db/migrate/20130306212430_add_deleted_at_to_discerner_search_parameters.rb +5 -0
  107. data/db/migrate/20130306212504_add_deleted_at_to_discerner_search_parameter_values.rb +5 -0
  108. data/db/migrate/20130306212527_add_deleted_at_to_discerner_search_combinations.rb +5 -0
  109. data/db/migrate/20130306212818_add_deleted_at_to_discerner_export_parameters.rb +5 -0
  110. data/db/migrate/20130311190717_add_operator_type_to_discerner_operators.rb +5 -0
  111. data/db/migrate/20131212175110_remove_extra_search_parameter_values.rb +10 -0
  112. data/db/migrate/20140204170625_create_discerner_parameter_value_categories.rb +16 -0
  113. data/db/migrate/20140204170646_create_discerner_parameter_value_categorizations.rb +12 -0
  114. data/db/migrate/20140227191827_remove_blank_parameter_values_from_export_parameters.rb +10 -0
  115. data/db/seeds.rb +0 -0
  116. data/lib/discerner/engine.rb +16 -0
  117. data/lib/discerner/methods/controllers/export_parameters_controller.rb +38 -0
  118. data/lib/discerner/methods/controllers/parameters_controller.rb +30 -0
  119. data/lib/discerner/methods/controllers/searches_controller.rb +204 -0
  120. data/lib/discerner/methods/helpers/searches_helper.rb +145 -0
  121. data/lib/discerner/methods/models/dictionary.rb +54 -0
  122. data/lib/discerner/methods/models/export_parameter.rb +35 -0
  123. data/lib/discerner/methods/models/operator.rb +42 -0
  124. data/lib/discerner/methods/models/parameter.rb +90 -0
  125. data/lib/discerner/methods/models/parameter_category.rb +60 -0
  126. data/lib/discerner/methods/models/parameter_type.rb +33 -0
  127. data/lib/discerner/methods/models/parameter_value.rb +87 -0
  128. data/lib/discerner/methods/models/parameter_value_categorization.rb +21 -0
  129. data/lib/discerner/methods/models/parameter_value_category.rb +45 -0
  130. data/lib/discerner/methods/models/search.rb +147 -0
  131. data/lib/discerner/methods/models/search_combination.rb +50 -0
  132. data/lib/discerner/methods/models/search_parameter.rb +128 -0
  133. data/lib/discerner/methods/models/search_parameter_value.rb +130 -0
  134. data/lib/discerner/methods/models/soft_delete.rb +35 -0
  135. data/lib/discerner/methods/models/warning.rb +15 -0
  136. data/lib/discerner/parser.rb +497 -0
  137. data/lib/discerner/version.rb +3 -0
  138. data/lib/discerner.rb +4 -0
  139. data/lib/generators/discerner/dictionary/dictionary_generator.rb +38 -0
  140. data/lib/generators/discerner/dictionary/templates/model.rb +15 -0
  141. data/lib/generators/discerner/dictionary/templates/show.xls.erb +37 -0
  142. data/lib/generators/discerner/dictionary/templates/view.html.haml +2 -0
  143. data/lib/generators/discerner/install/install_generator.rb +153 -0
  144. data/lib/generators/discerner/install/templates/controllers/export_parameters_controller.rb +20 -0
  145. data/lib/generators/discerner/install/templates/controllers/parameters_controller.rb +15 -0
  146. data/lib/generators/discerner/install/templates/controllers/searches_controller.rb +39 -0
  147. data/lib/generators/discerner/install/templates/dictionaries.yml +236 -0
  148. data/lib/generators/discerner/install/templates/helpers/searches_helper.rb +9 -0
  149. data/lib/generators/discerner/install/templates/models/book.rb +15 -0
  150. data/lib/generators/discerner/install/templates/models/dictionary.rb +9 -0
  151. data/lib/generators/discerner/install/templates/models/export_parameter.rb +9 -0
  152. data/lib/generators/discerner/install/templates/models/operator.rb +9 -0
  153. data/lib/generators/discerner/install/templates/models/parameter.rb +10 -0
  154. data/lib/generators/discerner/install/templates/models/parameter_category.rb +9 -0
  155. data/lib/generators/discerner/install/templates/models/parameter_type.rb +9 -0
  156. data/lib/generators/discerner/install/templates/models/parameter_value.rb +9 -0
  157. data/lib/generators/discerner/install/templates/models/parameter_value_categorization.rb +9 -0
  158. data/lib/generators/discerner/install/templates/models/parameter_value_category.rb +9 -0
  159. data/lib/generators/discerner/install/templates/models/search.rb +9 -0
  160. data/lib/generators/discerner/install/templates/models/search_combination.rb +9 -0
  161. data/lib/generators/discerner/install/templates/models/search_parameter.rb +9 -0
  162. data/lib/generators/discerner/install/templates/models/search_parameter_value.rb +9 -0
  163. data/lib/generators/discerner/install/templates/views/layouts/searches.html.erb +17 -0
  164. data/lib/setup/operators.yml +91 -0
  165. data/lib/tasks/cucumber.rake +65 -0
  166. data/lib/tasks/discerner_tasks.rake +30 -0
  167. metadata +531 -0
@@ -0,0 +1,497 @@
1
+ module Discerner
2
+ class Parser
3
+ attr_accessor :options, :errors, :updated_dictionaries, :updated_categories, :updated_parameters, :updated_parameter_value_categories, :updated_parameter_values, :blank_parameter_values
4
+
5
+ def initialize(options={})
6
+ self.options = options
7
+ self.errors = []
8
+ reset_counts
9
+ end
10
+
11
+ def reset_counts
12
+ self.updated_dictionaries = []
13
+ self.updated_categories = []
14
+ self.updated_parameters = []
15
+ self.updated_parameter_values = []
16
+ self.updated_parameter_value_categories = []
17
+ self.blank_parameter_values = []
18
+ end
19
+
20
+ def parse_dictionaries(str)
21
+ reset_counts
22
+ hash_from_file = YAML.load(str)
23
+
24
+ # find or initialize dictionaries
25
+ dictionaries_from_file = hash_from_file[:dictionaries]
26
+ error_message 'No dictionaries detected.' if dictionaries_from_file.blank?
27
+
28
+ Discerner::Dictionary.transaction do
29
+ dictionaries_from_file.each do |dictionary_from_file|
30
+ dictionary = parse_dictionary(dictionary_from_file)
31
+
32
+ ## find or initialize parameter categories
33
+ parameter_categories_from_file = dictionary_from_file[:parameter_categories]
34
+ error_message 'no parameter categories detected' if parameter_categories_from_file.blank?
35
+
36
+ parameter_categories_from_file.each do |parameter_category_from_file|
37
+ parameter_category = parse_parameter_category(dictionary, parameter_category_from_file)
38
+
39
+ ## find or initialize parameters
40
+ parameters_from_file = parameter_category_from_file[:parameters]
41
+ error_message 'no parameters detected' if parameters_from_file.blank?
42
+
43
+ parameters_from_file.each do |parameter_from_file|
44
+ parameter = parse_parameter(parameter_category, parameter_from_file)
45
+
46
+ search_identifiers = parameter_from_file[:search]
47
+ unless search_identifiers.blank?
48
+ ## find or initialize parameter value categories
49
+ unless search_identifiers[:parameter_value_categories].blank?
50
+ search_identifiers[:parameter_value_categories].each do |parameter_value_category_from_file|
51
+ parse_parameter_value_category(parameter, parameter_value_category_from_file)
52
+ end
53
+ end
54
+
55
+ unless search_identifiers[:parameter_value_categories_source].blank?
56
+ load_parameter_value_categories_from_source(parameter, search_identifiers[:parameter_value_categories_source])
57
+ end
58
+
59
+ ## find or initialize parameter values
60
+ unless search_identifiers[:parameter_values].blank?
61
+ search_identifiers[:parameter_values].each do |parameter_value_from_file|
62
+ parse_parameter_value(parameter, parameter_value_from_file)
63
+ end
64
+ end
65
+
66
+ unless search_identifiers[:source].blank?
67
+ load_parameter_value_from_source(parameter, search_identifiers[:source])
68
+ end
69
+
70
+ unless search_identifiers[:allow_empty_values] == false
71
+ blank_parameter_values << find_or_create_parameter_value(parameter, '', 'None', nil, true)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ notification_message "cleaing up ..."
79
+ cleanup unless errors.any?
80
+ end
81
+
82
+ def parse_dictionary(hash)
83
+ error_message 'dictionary definition was not provided' if hash.blank?
84
+
85
+ dictionary_name = hash[:name]
86
+ error_message 'dictionary name cannot be blank' if dictionary_name.blank?
87
+ notification_message "processing dictionary '#{dictionary_name}'"
88
+
89
+ dictionary = Discerner::Dictionary.find_or_initialize_by_name(dictionary_name)
90
+ dictionary.deleted_at = nil
91
+
92
+ if dictionary.new_record?
93
+ notification_message "creating dictionary ..."
94
+ dictionary.created_at = Time.now
95
+ else
96
+ notification_message "updating dictionary ..."
97
+ dictionary.updated_at = Time.now
98
+ end
99
+ error_message "dictionary could not be saved: #{dictionary.errors.full_messages}", dictionary_name unless dictionary.save
100
+ notification_message 'dictionary saved'
101
+ updated_dictionaries << dictionary
102
+ dictionary
103
+ end
104
+
105
+ def parse_parameter_category(dictionary, hash)
106
+ error_message 'parameter category definition was not provided' if hash.blank?
107
+
108
+ parameter_category_name = hash[:name]
109
+ error_message 'parameter category name cannot be blank' if parameter_category_name.blank?
110
+ notification_message "processing parameter category '#{parameter_category_name}'"
111
+
112
+ parameter_category = Discerner::ParameterCategory.where(:name => parameter_category_name, :dictionary_id => dictionary.id).first_or_initialize
113
+ parameter_category.deleted_at = nil
114
+
115
+ if parameter_category.new_record?
116
+ notification_message "creating parameter category ..."
117
+ parameter_category.created_at = Time.now
118
+ else
119
+ notification_message "updating parameter category ..."
120
+ parameter_category.updated_at = Time.now
121
+ end
122
+ error_message "parameter category could not be saved: #{parameter_category.errors.full_messages}", parameter_category_name unless parameter_category.save
123
+ notification_message 'parameter category saved'
124
+ updated_categories << parameter_category
125
+ parameter_category
126
+ end
127
+
128
+ def parse_parameter(parameter_category, hash)
129
+ error_message 'parameter definition was not provided' if hash.blank?
130
+
131
+ parameter_name = hash[:name]
132
+ error_message 'parameter name cannot be blank' if parameter_name.blank?
133
+
134
+ notification_message "processing parameter '#{parameter_name}'"
135
+ unique_identifier = hash[:unique_identifier]
136
+ error_message "unique_identifier cannot be blank", parameter_name if unique_identifier.blank?
137
+
138
+ existing_parameter = Discerner::Parameter.
139
+ includes({:parameter_category => :dictionary}).
140
+ where('discerner_parameters.unique_identifier = ? and discerner_dictionaries.id = ?', unique_identifier, parameter_category.dictionary.id).first
141
+ parameter = existing_parameter || Discerner::Parameter.new(:unique_identifier => unique_identifier, :parameter_category => parameter_category)
142
+
143
+ parameter.name = parameter_name
144
+ parameter.deleted_at = nil
145
+ parameter.exclusive = hash[:exclusive].nil? ? true : to_bool(hash[:exclusive])
146
+ parameter.parameter_category = parameter_category
147
+
148
+ search_identifiers = hash[:search]
149
+ unless search_identifiers.blank?
150
+ error_message "Searchable parameter should search model, search method and parameter_type defined." if
151
+ search_identifiers[:model].blank? || search_identifiers[:method].blank? || search_identifiers[:parameter_type].blank?
152
+
153
+ parameter.search_model = search_identifiers[:model].to_s
154
+ parameter.search_method = search_identifiers[:method].to_s
155
+ parameter.parameter_type = find_or_initialize_parameter_type(search_identifiers[:parameter_type])
156
+ end
157
+
158
+ export_identifiers = hash[:export]
159
+ unless export_identifiers.blank?
160
+ error_message "Exportable parameter should export model and export method defined." if
161
+ export_identifiers[:model].blank? || export_identifiers[:method].blank?
162
+
163
+ parameter.export_model = export_identifiers[:model].to_s
164
+ parameter.export_method = export_identifiers[:method].to_s
165
+ end
166
+
167
+ if parameter.new_record?
168
+ notification_message "creating parameter ..."
169
+ parameter.created_at = Time.now
170
+ else
171
+ notification_message "updating parameter ..."
172
+ parameter.updated_at = Time.now
173
+ end
174
+
175
+ error_message "parameter could not be saved: #{parameter.errors.full_messages}", parameter_name unless parameter.save
176
+ notification_message 'parameter saved'
177
+ updated_parameters << parameter
178
+ parameter
179
+ end
180
+
181
+ def parse_parameter_value(parameter, hash)
182
+ error_message 'parameter value definition was not provided' if hash.blank?
183
+ search_value = hash[:search_value]
184
+ error_message 'parameter value search_value cannot be blank' if search_value.nil?
185
+ find_or_create_parameter_value(parameter, search_value, hash[:name], hash[:parameter_value_category], false)
186
+ end
187
+
188
+ def parse_parameter_value_category(parameter, hash)
189
+ error_message 'parameter value category definition was not provided' if hash.blank?
190
+ unique_identifier = hash[:unique_identifier]
191
+ name = hash[:name]
192
+
193
+ error_message 'parameter value category unique_identifier cannot be blank' if unique_identifier.nil?
194
+ error_message 'parameter value category name cannot be blank' if name.nil?
195
+ find_or_create_parameter_value_category(parameter, unique_identifier, name, hash[:display_order], hash[:collapse])
196
+ end
197
+
198
+ def load_parameter_value_from_source(parameter, hash)
199
+ error_message 'parameter value definition was not provided' if hash.blank?
200
+
201
+ model_name = hash[:model]
202
+ method_name = hash[:method]
203
+ error_message "model and method must be defined for parameter source" if model_name.blank? || method_name.blank?
204
+
205
+ source_model = model_name.safe_constantize
206
+ error_message "model '#{model_name}' could not be found" if source_model.blank?
207
+
208
+ if source_model.respond_to?(method_name)
209
+ notification_message "method '#{method_name}' recognized as a class method"
210
+
211
+ parameter_values = source_model.send(method_name)
212
+
213
+ error_message "method '#{method_name}' did not return an array of values" if parameter_values.blank? || !parameter_values.kind_of?(Array)
214
+
215
+ if parameter_values.select { |parameter_value| !parameter_value.has_key?(:name) || !parameter_value.has_key?(:search_value) }.any?
216
+ error_message "method '#{method_name}' does not adhere to the interface"
217
+ end
218
+
219
+ parameter_values.map{|parameter_value| find_or_create_parameter_value(parameter, parameter_value[:search_value], parameter_value[:name], parameter_value[:parameter_value_category]) }
220
+ else
221
+ notification_message "method '#{method_name}' is not recognized as a class method, will try it on instance.."
222
+ error_message "model '#{model_name}' does no respond to :all method" if !source_model.respond_to?(:all)
223
+
224
+ search_value_sources = source_model.send(:all)
225
+ error_message "model '#{method_name}' did not return an array of instances" if search_value_sources.blank?
226
+
227
+ search_value_sources.each do |row|
228
+ error_message "model '#{model_name}' instance does no respond to #{method_name} method" if !row.respond_to?(method_name)
229
+ find_or_create_parameter_value(parameter, row.send(method_name))
230
+ end
231
+ end
232
+ end
233
+
234
+ def load_parameter_value_categories_from_source(parameter, hash)
235
+ error_message 'parameter value category definition was not provided' if hash.blank?
236
+
237
+ model_name = hash[:model]
238
+ method_name = hash[:method]
239
+ error_message "model and method must be defined for parameter value category source" if model_name.blank? || method_name.blank?
240
+
241
+ source_model = model_name.safe_constantize
242
+ error_message "model '#{model_name}' could not be found" if source_model.blank?
243
+
244
+ if source_model.respond_to?(method_name)
245
+ notification_message "method '#{method_name}' recognized as a class method"
246
+
247
+ parameter_value_categories = source_model.send(method_name)
248
+
249
+ error_message "method '#{method_name}' did not return an array of values" if parameter_value_categories.blank? || !parameter_value_categories.kind_of?(Array)
250
+
251
+ if parameter_value_categories.select { |parameter_value_category| !parameter_value_category.has_key?(:name) || !parameter_value_category.has_key?(:unique_identifier)}.any?
252
+ error_message "method '#{method_name}' does not adhere to the interface"
253
+ end
254
+
255
+ parameter_value_categories.map{|parameter_value_category| find_or_create_parameter_value_category(parameter, parameter_value_category[:unique_identifier], parameter_value_category[:name], parameter_value_category[:display_order], parameter_value_category[:collapse])}
256
+ else
257
+ notification_message "method '#{method_name}' is not recognized as a class method, will try it on instance.."
258
+ error_message "model '#{model_name}' does no respond to :all method" if !source_model.respond_to?(:all)
259
+
260
+ parameter_value_category_sources = source_model.send(:all)
261
+ error_message "model '#{method_name}' did not return an array of instances" if parameter_value_category_sources.blank?
262
+
263
+ parameter_value_category_sources.each do |row|
264
+ error_message "model '#{model_name}' instance does no respond to #{method_name} method" if !row.respond_to?(method_name)
265
+ find_or_create_parameter_value_category(parameter, row.send(method_name))
266
+ end
267
+ end
268
+ end
269
+
270
+ def parse_operators(str)
271
+ hash_from_file = YAML.load(str)
272
+
273
+ operators_from_file = hash_from_file[:operators]
274
+ error_message 'No operators detected in the file.' if operators_from_file.blank?
275
+
276
+ Discerner::Operator.transaction do
277
+ operators_from_file.each do |operator_from_file|
278
+ error_message 'unique identifier has to be defined' if operator_from_file[:unique_identifier].blank?
279
+
280
+ operator = Discerner::Operator.find_or_initialize_by_unique_identifier(operator_from_file[:unique_identifier])
281
+ if operator.new_record?
282
+ notification_message "creating operator '#{operator_from_file[:unique_identifier]}'"
283
+ operator.created_at = Time.now
284
+ else
285
+ notification_message "operator '#{operator_from_file[:unique_identifier]}' already exists and will be updated"
286
+ operator.updated_at = Time.now
287
+ end
288
+ operator.deleted_at = operator_from_file[:deleted].blank? ? nil : Time.now
289
+
290
+ unless operator_from_file[:parameter_types].blank?
291
+ operator.parameter_types.destroy_all
292
+
293
+ operator_from_file[:parameter_types].each do |parameter_type_from_file|
294
+ parameter_type = find_or_initialize_parameter_type(parameter_type_from_file)
295
+ operator.parameter_types << parameter_type
296
+ end
297
+ end
298
+ operator.symbol = operator_from_file[:symbol]
299
+ operator.text = operator_from_file[:text]
300
+ operator.operator_type = operator_from_file[:type]
301
+ #operator.deleted_at = operator_from_file[:deleted].blank? ? nil : Time.now
302
+ error_message "Operator could not be saved: #{operator.errors.full_messages}" unless operator.save
303
+ end
304
+ end
305
+ end
306
+
307
+ def find_or_initialize_parameter_type(name)
308
+ error_message "Parameter type name has to be provided" if name.blank?
309
+ error_message "'integer' parameter type has been replaced with 'numeric', please update your dictionary definition" if /integer/.match(name.downcase)
310
+
311
+ ## find or initialize parameter type
312
+ parameter_type = Discerner::ParameterType.find_or_initialize_by_name(name.downcase)
313
+ if parameter_type.new_record?
314
+ notification_message "Creating parameter type '#{name}'"
315
+ parameter_type.created_at = Time.now
316
+ else
317
+ notification_message "Parameter type '#{name}' already exists"
318
+ end
319
+ error_message "Parameter type #{name} could not be saved: #{parameter_type.errors.full_messages}" unless parameter_type.save
320
+ return parameter_type
321
+ end
322
+
323
+ def find_or_create_parameter_value(parameter, search_value, name=nil, parameter_value_category_identifier=nil, silent=nil)
324
+ error_message "search value was not provided" if search_value.nil?
325
+ search_value = search_value.to_s
326
+ notification_message "processing parameter value '#{search_value}'"
327
+
328
+ parameter_value = Discerner::ParameterValue.where(:search_value => search_value, :parameter_id => parameter.id).first_or_initialize
329
+ if parameter_value.new_record?
330
+ notification_message "creating parameter value ..."
331
+ parameter_value.created_at = Time.now
332
+ else
333
+ notification_message "updating parameter value ..."
334
+ parameter_value.updated_at = Time.now
335
+ end
336
+
337
+ unless parameter_value_category_identifier.blank?
338
+ parameter_value_category = Discerner::ParameterValueCategory.where(:unique_identifier => parameter_value_category_identifier, :parameter_id => parameter.id).first_or_initialize
339
+ if parameter_value_category.blank?
340
+ error_message "parameter value category with unique identifier #{parameter_value_category_identifier} is not found for parameter #{parameter.name}"
341
+ else
342
+ parameter_value.parameter_value_category = parameter_value_category
343
+ end
344
+ end
345
+
346
+ parameter_value.name = name || search_value
347
+ parameter_value.deleted_at = nil
348
+ error_message "parameter value #{search_value} could not be saved: #{parameter_value.errors.full_messages}" unless parameter_value.save
349
+ notification_message 'parameter value saved'
350
+ updated_parameter_values << parameter_value unless silent
351
+ parameter_value
352
+ end
353
+
354
+ def find_or_create_parameter_value_category(parameter, unique_identifier, name, display_order=0, collapse=nil)
355
+ error_message "unique_identifier was not provided" if unique_identifier.nil?
356
+ error_message "name was not provided" if name.nil?
357
+
358
+ unique_identifier = unique_identifier.to_s
359
+ notification_message "processing parameter value category '#{unique_identifier}'"
360
+
361
+ parameter_value_category = Discerner::ParameterValueCategory.where(:unique_identifier => unique_identifier, :parameter_id => parameter.id).first_or_initialize
362
+ if parameter_value_category.new_record?
363
+ notification_message "creating parameter value category..."
364
+ parameter_value_category.created_at = Time.now
365
+ else
366
+ notification_message "updating parameter value category ..."
367
+ parameter_value_category.updated_at = Time.now
368
+ end
369
+
370
+ parameter_value_category.name = name
371
+ parameter_value_category.display_order = display_order.to_i
372
+ parameter_value_category.collapse = collapse
373
+ parameter_value_category.deleted_at = nil
374
+ error_message "parameter value category #{unique_identifier} could not be saved: #{parameter_value_category.errors.full_messages}" unless parameter_value_category.save
375
+ notification_message 'parameter value category saved'
376
+ updated_parameter_value_categories << parameter_value_category
377
+ parameter_value_category
378
+ end
379
+
380
+ def error_message(str, target=nil)
381
+ errors << "#{target}: #{str}"
382
+ puts "ERROR: #{str}"
383
+ reset_counts
384
+ raise ActiveRecord::Rollback
385
+ end
386
+
387
+ def notification_message(str)
388
+ puts str unless self.options[:trace].blank?
389
+ end
390
+
391
+ def to_bool(s)
392
+ return true if s == true || s =~ (/^(true|t|yes|y|1)$/i)
393
+ return false if s == false || s.blank? || s =~ (/^(false|f|no|n|0)$/i)
394
+ error_message("invalid value for Boolean: \"#{s}\"")
395
+ end
396
+
397
+ def deleted?(param)
398
+ return false if param.blank?
399
+ to_bool(param)
400
+ end
401
+
402
+ private
403
+ def cleanup
404
+ cleanup_parameter_value_categories
405
+ cleanup_parameter_values
406
+ cleanup_parameters
407
+ cleanup_categories
408
+ cleanup_dictionaries
409
+ end
410
+
411
+ def cleanup_dictionaries
412
+ abandoned_dictionaries = Discerner::Dictionary.order(:id).to_a - updated_dictionaries
413
+ used_dictionaries = abandoned_dictionaries.reject{|d| d.searches.blank?}
414
+ not_used_dictionaries = abandoned_dictionaries - used_dictionaries
415
+
416
+ used_dictionaries.each do |r|
417
+ notification_message("marking dictionary #{r.name} as deleted");
418
+ r.deleted_at = Time.now
419
+ error_message "dictionary could not be updated: #{r.errors.full_messages}", r.name unless r.save
420
+ end
421
+
422
+ unless not_used_dictionaries.blank?
423
+ notification_message("permanently deleting dictionaries #{not_used_dictionaries.map{|r| r.name}.join(', ')}");
424
+ not_used_dictionaries.each{|r| r.destroy}
425
+ end
426
+ end
427
+
428
+ def cleanup_categories
429
+ abandoned_categories = Discerner::ParameterCategory.order(:id).to_a - updated_categories
430
+ used_categories = abandoned_categories.reject{|c| c.parameters.blank? || c.parameters.select{|p| p.used_in_search?}.blank?}
431
+ not_used_categories = abandoned_categories - used_categories
432
+
433
+ used_categories.each do |r|
434
+ notification_message("marking parameter category #{r.name} as deleted");
435
+ r.deleted_at = Time.now
436
+ error_message "parameter category could not be deleted: #{r.errors.full_messages}", r.name unless r.save
437
+ end
438
+
439
+ unless not_used_categories.blank?
440
+ notification_message("permanently deleting parameter categories #{not_used_categories.map{|r| r.name}.join(', ')}");
441
+ not_used_categories.each{|r| r.destroy}
442
+ end
443
+ end
444
+
445
+ def cleanup_parameters
446
+ abandoned_parameters = Discerner::Parameter.order(:id).to_a - updated_parameters
447
+ used_parameters = abandoned_parameters.select{|p| p.used_in_search?}
448
+ not_used_parameters = abandoned_parameters - used_parameters
449
+
450
+ used_parameters.each do |r|
451
+ notification_message("marking parameter #{r.name} as deleted");
452
+ r.deleted_at = Time.now
453
+ error_message "parameter could not be deleted: #{r.errors.full_messages}", r.name unless r.save
454
+ end
455
+
456
+ unless not_used_parameters.blank?
457
+ notification_message("permanently deleting parameters #{not_used_parameters.map{|r| r.name}.join(', ')}");
458
+ not_used_parameters.each{|r| r.destroy}
459
+ end
460
+ end
461
+
462
+ def cleanup_parameter_value_categories
463
+ abandoned_categories = Discerner::ParameterValueCategory.order(:id).to_a - updated_parameter_value_categories
464
+ used_categories = abandoned_categories.reject{|c| c.parameter_values.blank? || c.parameter_values.select{|v| v.used_in_search?}.blank?}
465
+ not_used_categories = abandoned_categories - used_categories
466
+
467
+ used_categories.each do |r|
468
+ notification_message("marking parameter value category #{r.name} as deleted");
469
+ r.deleted_at = Time.now
470
+ error_message "parameter value category could not be deleted: #{r.errors.full_messages}", r.name unless r.save
471
+ end
472
+
473
+ unless not_used_categories.blank?
474
+ notification_message("permanently deleting parameter categories #{not_used_categories.map{|r| r.name}.join(', ')}");
475
+ not_used_categories.each{|r| r.destroy}
476
+ end
477
+ end
478
+ # this also marks search_parameter_values that reference this value and are chosen as deleted
479
+ # and destroys search_parameter_values that reference this value but are not chosen (list options)
480
+ def cleanup_parameter_values
481
+ abandoned_parameter_values = Discerner::ParameterValue.order(:id).to_a - updated_parameter_values - blank_parameter_values
482
+ used_parameter_values = abandoned_parameter_values.select{|p| p.used_in_search?}
483
+ not_used_parameter_values = abandoned_parameter_values - used_parameter_values
484
+
485
+ used_parameter_values.each do |r|
486
+ notification_message("marking parameter value #{r.name} as deleted");
487
+ r.deleted_at = Time.now
488
+ error_message "parameter value could not be marked as deleted: #{r.errors.full_messages}", r.name unless r.save
489
+ end
490
+
491
+ unless not_used_parameter_values.blank?
492
+ notification_message("permanently deleting parameter values #{not_used_parameter_values.map{|r| r.name}.join(', ')}");
493
+ not_used_parameter_values.each{|r| r.destroy}
494
+ end
495
+ end
496
+ end
497
+ end
@@ -0,0 +1,3 @@
1
+ module Discerner
2
+ VERSION = "1.1.18"
3
+ end
data/lib/discerner.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "discerner/engine"
2
+
3
+ module Discerner
4
+ end
@@ -0,0 +1,38 @@
1
+ module Discerner
2
+ class DictionaryGenerator < Rails::Generators::Base
3
+ class_option "no-load", :type => :boolean
4
+ class_option "no-models", :type => :boolean
5
+ class_option "no-views", :type => :boolean
6
+
7
+ source_root File.expand_path('../templates', __FILE__)
8
+ argument :dictionary_file_path, :type => :string
9
+
10
+ def parse_dictionary_file
11
+ rake("discerner:setup:dictionaries FILE=#{dictionary_file_path}") unless options["no-load"]
12
+ end
13
+
14
+ def create_stub_dictionary_files
15
+ Discerner::Dictionary.not_deleted.each do |dictionary|
16
+ create_dictionary_class(dictionary) unless options["no-models"]
17
+ create_dictionary_view(dictionary) unless options["no-views"]
18
+ end
19
+ end
20
+
21
+ def add_excel_mime_type
22
+ inject_into_file("#{Rails.root}/config/initializers/mime_types.rb", 'Mime::Type.register "application/xls", :xls', :after => "# Be sure to restart your server when you modify this file.\n")
23
+ end
24
+
25
+ private
26
+ def create_dictionary_class(dictionary)
27
+ @class_name = dictionary.parameterized_name.camelize
28
+ template "model.rb", "#{Rails.root}/app/models/#{dictionary.parameterized_name}.rb"
29
+ end
30
+
31
+ def create_dictionary_view(dictionary)
32
+ @dictionary_name = dictionary.name
33
+ empty_directory "#{Rails.root}/app/views/discerner/dictionaries/#{dictionary.parameterized_name}"
34
+ template "view.html.haml", "#{Rails.root}/app/views/discerner/dictionaries/#{dictionary.parameterized_name}/_results.html.haml"
35
+ template "show.xls.erb", "#{Rails.root}/app/views/discerner/dictionaries/#{dictionary.parameterized_name}/show.xls.erb"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ class <%= @class_name %>
2
+ attr_accessor :search
3
+
4
+ def initialize(search)
5
+ @search = search
6
+ end
7
+
8
+ def search(params = {}, options = {})
9
+
10
+ end
11
+
12
+ def export(params = {}, options = {})
13
+
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ <?xml version="1.0"?>
2
+ <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
3
+ xmlns:o="urn:schemas-microsoft-com:office:office"
4
+ xmlns:x="urn:schemas-microsoft-com:office:excel"
5
+ xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
6
+ xmlns:html="http://www.w3.org/TR/REC-html40">
7
+ <Worksheet ss:Name="Sheet1">
8
+ <Table>
9
+ <Row>
10
+ <Cell><Data ss:Type="String">ID</Data></Cell>
11
+ <Cell><Data ss:Type="String">Name</Data></Cell>
12
+ <Cell><Data ss:Type="String">Release Date</Data></Cell>
13
+ <Cell><Data ss:Type="String">Price</Data></Cell>
14
+ </Row>
15
+ </Table>
16
+ </Worksheet>
17
+ <Worksheet ss:Name="Sheet2">
18
+ <Table>
19
+ <Row>
20
+ <Cell><Data ss:Type="String">ID</Data></Cell>
21
+ <Cell><Data ss:Type="String">Name</Data></Cell>
22
+ <Cell><Data ss:Type="String">Release Date</Data></Cell>
23
+ <Cell><Data ss:Type="String">Price</Data></Cell>
24
+ </Row>
25
+ </Table>
26
+ </Worksheet>
27
+ <Worksheet ss:Name="Sheet3">
28
+ <Table>
29
+ <Row>
30
+ <Cell><Data ss:Type="String">ID</Data></Cell>
31
+ <Cell><Data ss:Type="String">Name</Data></Cell>
32
+ <Cell><Data ss:Type="String">Release Date</Data></Cell>
33
+ <Cell><Data ss:Type="String">Price</Data></Cell>
34
+ </Row>
35
+ </Table>
36
+ </Worksheet>
37
+ </Workbook>
@@ -0,0 +1,2 @@
1
+ %p
2
+ Results for search on the `<%=@dictionary_name %>` dictionary can be added here