rexport 0.5.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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