rexport 0.5.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/Rakefile +6 -34
  3. data/app/views/export_filters/_export_filter.html.erb +2 -2
  4. data/app/views/export_items/_export_item.html.erb +2 -2
  5. data/app/views/exports/_edit.html.erb +2 -2
  6. data/app/views/exports/_filters.html.erb +1 -1
  7. data/app/views/exports/_form.html.erb +6 -6
  8. data/app/views/exports/_rexport_model.html.erb +1 -1
  9. data/app/views/exports/_show.html.erb +6 -6
  10. data/app/views/exports/edit.html.erb +1 -1
  11. data/app/views/exports/index.html.erb +5 -5
  12. data/app/views/exports/new.html.erb +2 -2
  13. data/app/views/exports/show.html.erb +1 -1
  14. data/config/routes.rb +6 -6
  15. data/db/migrate/20091105182959_create_export_tables.rb +3 -3
  16. data/lib/rexport.rb +3 -1
  17. data/lib/rexport/data_field.rb +17 -0
  18. data/lib/rexport/data_fields.rb +25 -56
  19. data/lib/rexport/export_filter_methods.rb +46 -24
  20. data/lib/rexport/export_item_methods.rb +29 -34
  21. data/lib/rexport/export_methods.rb +161 -208
  22. data/lib/rexport/exports_controller_methods.rb +22 -28
  23. data/lib/rexport/rexport_model.rb +33 -0
  24. data/lib/rexport/tree_node.rb +13 -16
  25. data/lib/rexport/version.rb +1 -1
  26. data/test/factories.rb +58 -53
  27. data/test/test_helper.rb +29 -33
  28. data/test/unit/data_field_test.rb +11 -11
  29. data/test/unit/data_fields_test.rb +137 -95
  30. data/test/unit/export_filter_methods_test.rb +37 -0
  31. data/test/unit/export_item_methods_test.rb +21 -0
  32. data/test/unit/export_methods_test.rb +185 -59
  33. data/test/unit/rexport_model_test.rb +12 -12
  34. data/test/unit/tree_node_test.rb +20 -20
  35. metadata +14 -26
  36. data/test/jenkins.bash +0 -3
  37. data/test/log/test.log +0 -3891
@@ -1,45 +1,40 @@
1
1
  module Rexport #:nodoc:
2
2
  module ExportItemMethods
3
- def self.included(base)
4
- base.extend ClassMethods
5
- base.class_eval do
6
- include InstanceMethods
7
-
8
- acts_as_list :scope => :export
9
- belongs_to :export
10
- before_validation :replace_blank_name_with_rexport_field
11
- validates_presence_of :name, :rexport_field
12
- scope :ordered, -> { order :position }
13
- end
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ acts_as_list scope: :export
7
+
8
+ belongs_to :export
9
+
10
+ before_validation :replace_blank_name_with_rexport_field
11
+ validates_presence_of :name, :rexport_field
12
+
13
+ scope :ordered, -> { order :position }
14
14
  end
15
-
15
+
16
16
  module ClassMethods
17
17
  def resort(export_item_ids)
18
- export_item_ids.each_index do |index|
19
- position = index + 1
20
- export_item = find(export_item_ids[index].gsub(/[^0-9]/,''))
21
- export_item.update_attribute(:position, position) if export_item.position != position
18
+ transaction do
19
+ export_item_ids.each_with_index do |id, index|
20
+ find(id.gsub(/[^0-9]/, '')).update_attribute(:position, index + 1)
21
+ end
22
22
  end
23
23
  end
24
24
  end
25
-
26
- module InstanceMethods
27
- def attributes_for_copy
28
- attributes.slice('position', 'name', 'rexport_field')
29
- end
30
-
31
- #######
32
- private
33
- #######
34
-
35
- def replace_blank_name_with_rexport_field
36
- return unless name.blank?
37
- self.name = if rexport_field.include?('.')
38
- rexport_field.split('.').values_at(-2..-1).map {|v| v.titleize}.join(' - ')
39
- else
40
- rexport_field.titleize
41
- end
42
- end
25
+
26
+ def attributes_for_copy
27
+ attributes.slice('position', 'name', 'rexport_field')
28
+ end
29
+
30
+ private
31
+
32
+ def replace_blank_name_with_rexport_field
33
+ self.name = generate_name_from_rexport_field if name.blank?
34
+ end
35
+
36
+ def generate_name_from_rexport_field
37
+ rexport_field.split('.').last(2).map(&:titleize).join(' - ')
43
38
  end
44
39
  end
45
40
  end
@@ -1,272 +1,225 @@
1
1
  require 'csv'
2
2
 
3
3
  module Rexport #:nodoc:
4
+ module ExportMethods
5
+ extend ActiveSupport::Concern
4
6
 
5
- SAMPLE_SIZE = 5
6
-
7
- class RexportModel
8
- attr_accessor :klass, :path
9
-
10
- def initialize(klass, path = nil)
11
- self.klass = klass
12
- self.path = path.to_s unless path.blank?
13
- end
14
-
15
- def rexport_fields_array
16
- klass.rexport_fields_array
17
- end
18
-
19
- def field_path(field_name)
20
- [path, field_name].compact * '.'
21
- end
22
-
23
- def collection_from_association(association)
24
- return klass.send("find_#{association}_for_rexport") if klass.respond_to?("find_#{association}_for_rexport")
25
- klass.reflect_on_association(association.to_sym).klass.all
26
- end
7
+ included do
8
+ has_many :export_items, dependent: :destroy
9
+ has_many :export_filters, dependent: :destroy
27
10
 
28
- def filter_column(field)
29
- return field.method unless field.method.include?('.')
30
- association = field.method.split('.').first
31
- klass.reflect_on_association(association.to_sym).foreign_key
32
- end
11
+ validates_presence_of :name, :model_class_name
33
12
 
34
- def name
35
- klass.name
36
- end
37
- end
13
+ after_save :save_export_items
38
14
 
39
- module ExportMethods
40
- def self.included(base)
41
- base.extend ClassMethods
42
- base.class_eval do
43
- include InstanceMethods
44
-
45
- has_many :export_items, :dependent => :destroy
46
- has_many :export_filters, :dependent => :destroy
47
- validates_presence_of :name, :model_class_name
48
- after_save :save_export_items
49
- scope :alphabetical, -> { order :name }
50
- scope :categorical, -> { order :model_class_name }
51
- scope :by_model, ->(model_class_name) { where(model_class_name: model_class_name) }
52
- end
15
+ scope :alphabetical, -> { order :name }
16
+ scope :categorical, -> { order :model_class_name }
53
17
  end
54
18
 
55
19
  module ClassMethods
56
20
  def models
57
21
  %w(override_this_method)
58
22
  end
59
-
60
- def enabled
61
- find(:all).select {|export| export.enabled? }
62
- end
63
23
  end
64
24
 
65
- module InstanceMethods
66
- def full_name
67
- "#{model_class_name.pluralize} - #{name}"
68
- end
25
+ def full_name
26
+ "#{model_class_name.pluralize} - #{name}"
27
+ end
69
28
 
70
- # Returns a string with the export data
71
- def to_s
72
- String.new.tap do |result|
73
- result << header * '|' << "\n"
74
- records.each do |record|
75
- result << record * '|' << "\n"
76
- end
29
+ # Returns a string with the export data
30
+ def to_s
31
+ String.new.tap do |result|
32
+ result << header * '|' << "\n"
33
+ records.each do |record|
34
+ result << record * '|' << "\n"
77
35
  end
78
36
  end
37
+ end
79
38
 
80
- # Returns a csv string with the export data
81
- def to_csv(objects = nil)
82
- seed_records(objects) unless objects.nil?
83
- CSV.generate do |csv|
84
- csv << header
85
- records.each do |record|
86
- csv << record
87
- end
39
+ # Returns a csv string with the export data
40
+ def to_csv(objects = nil)
41
+ seed_records(objects) unless objects.nil?
42
+ CSV.generate do |csv|
43
+ csv << header
44
+ records.each do |record|
45
+ csv << record
88
46
  end
89
47
  end
48
+ end
90
49
 
91
- # Returns an array with the header names from the associated export_items
92
- def header
93
- export_items.ordered.map {|i| i.name}
94
- end
50
+ # Returns an array with the header names from the associated export_items
51
+ def header
52
+ export_items.ordered.map(&:name)
53
+ end
95
54
 
96
- # Returns the export model class
97
- def export_model
98
- model_class_name.constantize
99
- end
55
+ # Returns the export model class
56
+ def export_model
57
+ model_class_name.constantize
58
+ end
100
59
 
101
- # Returns an array of RexportModels including export_model and associated rexport capable models
102
- def rexport_models
103
- @rexport_models ||= get_rexport_models(export_model)
104
- end
60
+ # Returns an array of RexportModels including export_model and associated rexport capable models
61
+ def rexport_models
62
+ @rexport_models ||= get_rexport_models(export_model)
63
+ end
105
64
 
106
- # Returns the records for the export
107
- def records
108
- @records ||= get_records
109
- end
65
+ # Returns the records for the export
66
+ def records
67
+ @records ||= get_records
68
+ end
110
69
 
111
- # Returns a limited number of records for the export
112
- def sample_records
113
- get_records(Rexport::SAMPLE_SIZE)
114
- end
70
+ # Returns a limited number of records for the export
71
+ def sample_records
72
+ get_records(Rexport::SAMPLE_SIZE)
73
+ end
115
74
 
116
- # Returns a class based on a path array
117
- def get_klass_from_path(path, klass = export_model)
118
- return klass unless (association_name = path.shift)
119
- get_klass_from_path(path, klass.reflect_on_association(association_name.to_sym).klass)
120
- end
75
+ # Returns a class based on a path array
76
+ def get_klass_from_path(path, klass = export_model)
77
+ return klass unless (association_name = path.shift)
78
+ get_klass_from_path(path, klass.reflect_on_association(association_name.to_sym).klass)
79
+ end
121
80
 
122
- def has_rexport_field?(rexport_field)
123
- rexport_fields.include?(rexport_field)
124
- end
81
+ def has_rexport_field?(rexport_field)
82
+ rexport_fields.include?(rexport_field)
83
+ end
125
84
 
126
- def rexport_fields=(rexport_fields)
127
- @rexport_fields = if rexport_fields.respond_to?(:keys)
128
- @set_position = false
129
- rexport_fields.keys
130
- else
131
- @set_position = true
132
- rexport_fields
133
- end
85
+ def rexport_fields=(rexport_fields)
86
+ @rexport_fields = if rexport_fields.respond_to?(:keys)
87
+ @set_position = false
88
+ rexport_fields.keys.map(&:to_s)
89
+ else
90
+ @set_position = true
91
+ rexport_fields.map(&:to_s)
134
92
  end
93
+ end
135
94
 
136
- def export_filter_attributes=(attributes)
137
- attributes.each do |field, value|
138
- if value.blank?
139
- filter = export_filters.find_by(filter_field: field)
140
- filter.destroy if filter
141
- elsif new_record?
142
- export_filters.build(:filter_field => field, :value => value)
143
- else
144
- filter = export_filters.find_or_create_by(filter_field: field)
145
- filter.update_attribute(:value, value)
146
- end
95
+ def export_filter_attributes=(attributes)
96
+ attributes.each do |field, value|
97
+ if value.blank?
98
+ filter = export_filters.find_by(filter_field: field)
99
+ filter.destroy if filter
100
+ elsif new_record?
101
+ export_filters.build(filter_field: field, value: value)
102
+ else
103
+ filter = export_filters.find_or_create_by(filter_field: field)
104
+ filter.update_attribute(:value, value)
147
105
  end
148
106
  end
107
+ end
149
108
 
150
- def filter_value(filter_field)
151
- filter = export_filters.detect {|f| f.filter_field == filter_field}
152
- filter ? filter.value : nil
153
- end
154
-
155
- def copy
156
- self.class.create(attributes_for_copy) do |new_export|
157
- export_items.ordered.each { |item| new_export.export_items.build(item.attributes_for_copy) }
158
- export_filters.each { |filter| new_export.export_filters.build(filter.attributes_for_copy) }
159
- end
160
- end
109
+ def filter_value(filter_field)
110
+ export_filters.detect { |f| f.filter_field == filter_field }&.value
111
+ end
161
112
 
162
- def modifiable?
163
- # override to disable edit and destroy links for specific exports
164
- true
113
+ def copy
114
+ self.class.create(attributes_for_copy) do |new_export|
115
+ export_items.ordered.each { |item| new_export.export_items.build(item.attributes_for_copy) }
116
+ export_filters.each { |filter| new_export.export_filters.build(filter.attributes_for_copy) }
165
117
  end
118
+ end
166
119
 
167
- def enabled?
168
- export_model.count > 0
169
- end
120
+ def modifiable?
121
+ # override to disable edit and destroy links for specific exports
122
+ true
123
+ end
170
124
 
171
- #########
172
- protected
173
- #########
125
+ private
174
126
 
175
- def get_records(limit = nil)
176
- get_export_values(export_model.where(build_conditions).includes(build_include).limit(limit))
177
- end
127
+ def get_records(limit = nil)
128
+ get_export_values(export_model.where(build_conditions).includes(build_include).limit(limit))
129
+ end
178
130
 
179
- def seed_records(objects)
180
- @records = get_export_values(objects)
181
- end
131
+ def seed_records(objects)
132
+ @records = get_export_values(objects)
133
+ end
182
134
 
183
- def get_export_values(objects)
184
- objects.map { |object| object.export(rexport_methods) }
185
- end
135
+ def get_export_values(objects)
136
+ objects.map { |object| object.export(rexport_methods) }
137
+ end
186
138
 
187
- def get_rexport_models(rexport_model, result = [], path = nil)
188
- return unless rexport_model.respond_to?(:rexport_fields)
189
- result << RexportModel.new(rexport_model, path)
190
- get_associations(rexport_model).each do |associated_model|
191
- # prevent infinite loop by checking if this class is already in the result set
192
- unless result.detect { |rexport_model| rexport_model.klass == associated_model.klass }
193
- get_rexport_models(associated_model.klass, result, [path, associated_model.name].compact * '.')
194
- end
139
+ def get_rexport_models(rexport_model, result = [], path = nil)
140
+ return unless rexport_model.respond_to?(:rexport_fields)
141
+ result << RexportModel.new(rexport_model, path)
142
+ get_associations(rexport_model).each do |associated_model|
143
+ # prevent infinite loop by checking if this class is already in the result set
144
+ unless result.detect { |model| model.klass == associated_model.klass }
145
+ get_rexport_models(associated_model.klass, result, [path, associated_model.name].compact * '.')
195
146
  end
196
- return result
197
147
  end
148
+ return result
149
+ end
198
150
 
199
- def get_associations(rexport_model)
200
- (rexport_model.reflect_on_all_associations(:belongs_to) + rexport_model.reflect_on_all_associations(:has_one)).reject(&:polymorphic?)
201
- end
151
+ def get_associations(rexport_model)
152
+ %i(belongs_to has_one).map do |type|
153
+ rexport_model.reflect_on_all_associations(type)
154
+ end.flatten.reject(&:polymorphic?)
155
+ end
202
156
 
203
- def build_include
204
- root = Rexport::TreeNode.new('root')
205
- (rexport_methods + filter_fields).select {|m| m.include?('.')}.each do |method|
206
- root.add_child(method.split('.').values_at(0..-2))
207
- end
208
- root.to_include
157
+ def build_include
158
+ root = Rexport::TreeNode.new('root')
159
+ (rexport_methods + filter_fields).select {|m| m.include?('.')}.each do |method|
160
+ root.add_child(method.split('.').values_at(0..-2))
209
161
  end
162
+ root.to_include
163
+ end
210
164
 
211
- def build_conditions
212
- Hash.new.tap do |conditions|
213
- export_filters.each do |filter|
214
- conditions[get_database_field(filter.filter_field)] = filter.value
215
- end
165
+ def build_conditions
166
+ Hash.new.tap do |conditions|
167
+ export_filters.each do |filter|
168
+ conditions[get_database_field(filter.filter_field)] = filter.value
216
169
  end
217
170
  end
171
+ end
218
172
 
219
- def get_database_field(field)
220
- path = field.split('.')
221
- field = path.pop
222
- "#{get_klass_from_path(path).table_name}.#{field}"
223
- end
173
+ def get_database_field(field)
174
+ path = field.split('.')
175
+ field = path.pop
176
+ "#{get_klass_from_path(path).table_name}.#{field}"
177
+ end
224
178
 
225
- def rexport_methods
226
- @rexport_methods ||= export_model.get_rexport_methods(ordered_rexport_fields)
227
- end
179
+ def rexport_methods
180
+ @rexport_methods ||= export_model.get_rexport_methods(ordered_rexport_fields)
181
+ end
228
182
 
229
- def rexport_fields
230
- @rexport_fields ||= export_items.map {|i| i.rexport_field}
231
- end
183
+ def rexport_fields
184
+ @rexport_fields ||= export_items.map(&:rexport_field)
185
+ end
232
186
 
233
- def ordered_rexport_fields
234
- export_items.ordered.map {|i| i.rexport_field}
235
- end
187
+ def ordered_rexport_fields
188
+ export_items.ordered.map(&:rexport_field)
189
+ end
236
190
 
237
- def filter_fields
238
- export_filters.map {|f| f.filter_field}
239
- end
191
+ def filter_fields
192
+ export_filters.map(&:filter_field)
193
+ end
240
194
 
241
- def save_export_items
242
- export_items.each do |export_item|
243
- unless rexport_fields.include?(export_item.rexport_field)
244
- export_item.destroy
245
- end
195
+ def save_export_items
196
+ export_items.each do |export_item|
197
+ unless rexport_fields.include?(export_item.rexport_field)
198
+ export_item.destroy
246
199
  end
200
+ end
247
201
 
248
- export_items.reset
202
+ position = 0
203
+ rexport_fields.each do |rexport_field|
204
+ position += 1
205
+ export_item = export_items.detect { |i| i.rexport_field == rexport_field } || export_items.create(rexport_field: rexport_field)
206
+ export_item.update_attribute(:position, position) if set_position
207
+ end
249
208
 
250
- position = 0
251
- rexport_fields.each do |rexport_field|
252
- position += 1
253
- export_item = export_items.detect {|i| i.rexport_field == rexport_field } || export_items.create(:rexport_field => rexport_field)
254
- export_item.update_attribute(:position, position) if @set_position && export_item.position != position
255
- end
209
+ return true
210
+ end
256
211
 
257
- export_items.reset
258
- @rexport_fields = nil
259
- return true
260
- end
261
-
262
- def attributes_for_copy
263
- attributes.slice('model_class_name', 'description').merge(name: find_unique_name(self.name))
264
- end
212
+ def attributes_for_copy
213
+ attributes.slice('model_class_name', 'description').merge(name: find_unique_name(name))
214
+ end
265
215
 
266
- def find_unique_name(original_name, suffix = 0)
267
- new_name = suffix == 0 ? "#{original_name} Copy" : "#{original_name} Copy [#{suffix}]"
268
- self.class.find_by(name: new_name) ? find_unique_name(original_name, suffix += 1) : new_name
269
- end
216
+ def find_unique_name(original_name, suffix = 0)
217
+ new_name = suffix == 0 ? "#{original_name} Copy" : "#{original_name} Copy [#{suffix}]"
218
+ self.class.find_by(name: new_name) ? find_unique_name(original_name, suffix += 1) : new_name
219
+ end
220
+
221
+ def set_position
222
+ @set_position ||= false
270
223
  end
271
224
  end
272
225
  end