rexport 0.4.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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +17 -0
  4. data/Rakefile +38 -0
  5. data/app/helpers/exports_helper.rb +25 -0
  6. data/app/views/export_filters/_export_filter.html.erb +7 -0
  7. data/app/views/export_items/_export_item.html.erb +8 -0
  8. data/app/views/export_items/edit.html.erb +15 -0
  9. data/app/views/exports/_edit.html.erb +7 -0
  10. data/app/views/exports/_filters.html.erb +9 -0
  11. data/app/views/exports/_form.html.erb +25 -0
  12. data/app/views/exports/_local_form.html.erb +1 -0
  13. data/app/views/exports/_rexport_model.html.erb +17 -0
  14. data/app/views/exports/_show.html.erb +53 -0
  15. data/app/views/exports/edit.html.erb +1 -0
  16. data/app/views/exports/index.html.erb +33 -0
  17. data/app/views/exports/new.html.erb +7 -0
  18. data/app/views/exports/show.html.erb +1 -0
  19. data/config/routes.rb +11 -0
  20. data/db/migrate/20091105182959_create_export_tables.rb +34 -0
  21. data/lib/rexport.rb +17 -0
  22. data/lib/rexport/data_fields.rb +152 -0
  23. data/lib/rexport/export_filter_methods.rb +34 -0
  24. data/lib/rexport/export_filters_controller_methods.rb +13 -0
  25. data/lib/rexport/export_item_methods.rb +45 -0
  26. data/lib/rexport/export_item_sortings_controller_methods.rb +13 -0
  27. data/lib/rexport/export_items_controller_methods.rb +32 -0
  28. data/lib/rexport/export_methods.rb +272 -0
  29. data/lib/rexport/exports_controller_methods.rb +86 -0
  30. data/lib/rexport/tree_node.rb +45 -0
  31. data/lib/rexport/version.rb +3 -0
  32. data/test/factories.rb +86 -0
  33. data/test/jenkins.bash +3 -0
  34. data/test/log/test.log +61761 -0
  35. data/test/test_helper.rb +168 -0
  36. data/test/unit/data_field_test.rb +25 -0
  37. data/test/unit/data_fields_test.rb +117 -0
  38. data/test/unit/export_methods_test.rb +97 -0
  39. data/test/unit/rexport_model_test.rb +35 -0
  40. data/test/unit/tree_node_test.rb +43 -0
  41. metadata +165 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: aac4ec78dc853794fb76c0f05eaa383faca03e52
4
+ data.tar.gz: d2a1a8f5d7441d50acaf2cf129baf4dfbbd32017
5
+ SHA512:
6
+ metadata.gz: cbaa46236aac25bbc9c23210cd6a87dd787418f169fa20f85b5244f7b1b7bb9a32cfba424a36bbded225c767256493a3e6066ef9d849cb5324448f74d995dd8d
7
+ data.tar.gz: 03ab41bbedd051d566e7a9cfa8cae3ff5b710084facc4b8a27536d1c903abee5f62f65416876131bbe0b8bca74241da97f4299cd9fb2f41def6f8a95714bc54f
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Aaron Baldwin, WWIDEA INC.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ =Rexport
2
+
3
+ Ruby on Rails gem to manage exports
4
+
5
+
6
+ ==Installation
7
+ 1. install gem
8
+ 2. copy migration into application db/migrate folder and run
9
+ 3. create models and mix in corresponding module
10
+ * export => export_methods
11
+ * export_item => export_item_methods
12
+ * export_filter => export_filter_methods
13
+
14
+
15
+ ==License
16
+
17
+ Copyright (c) 2008-2012 WWIDEA, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Rexport'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,25 @@
1
+ module ExportsHelper
2
+ def filter_value_field(rexport_model, field)
3
+ filter_field = rexport_model.field_path(rexport_model.filter_column(field))
4
+ tag_name = "export[export_filter_attributes][#{filter_field.to_s}]"
5
+ value = @export.filter_value(filter_field)
6
+
7
+ case field.type
8
+ when :boolean
9
+ select_tag(tag_name, options_for_select([nil, ['true', 1], ['false', 0]], (value.to_i unless value.nil?)))
10
+ when :association
11
+ association, text_method = field.method.split('.')
12
+ select_tag( tag_name,
13
+ ('<option value=""></option>' +
14
+ options_from_collection_for_select(
15
+ rexport_model.collection_from_association(association),
16
+ :id,
17
+ text_method,
18
+ value.to_i)).html_safe)
19
+ when :datetime, nil
20
+ '&nbsp;'.html_safe
21
+ else
22
+ text_field_tag(tag_name, value)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ <tr class="<%= cycle('odd','even') %>">
2
+ <td class="row_title"><%= export_filter.filter_field %></td>
3
+ <td><%= export_filter.display_value %></td>
4
+ <td class="table_icons">
5
+ <%= link_to_delete(export_filter, :text => false) %>
6
+ </td>
7
+ </tr>
@@ -0,0 +1,8 @@
1
+ <tr id="<%= dom_id(export_item) %>" class="<%= cycle('odd','even') %> <%= @export.modifiable? ? 'handle' : '' %>">
2
+ <td class="row_title"><%= export_item.name %></td>
3
+ <td><%= export_item.rexport_field %></td>
4
+ <td class="table_icons">
5
+ <%= link_to(image_tag('icon_edit.gif'), edit_export_item_path(export_item)) if @export.modifiable? %>
6
+ <%= link_to_delete(export_item, :text => false) if @export.modifiable? %>
7
+ </td>
8
+ </tr>
@@ -0,0 +1,15 @@
1
+ <h1>Editing Export Item</h1>
2
+
3
+ <%= form_for(@export_item) do |f| %>
4
+ <%= f.error_messages %>
5
+
6
+ <p>
7
+ <%= f.label :name %><br />
8
+ <%= f.text_field :name %>
9
+ </p>
10
+ <p>
11
+ <%= f.submit "Update" %>
12
+ </p>
13
+ <% end %>
14
+
15
+ <%= link_to_cancel export_path(@export_item.export) %>
@@ -0,0 +1,7 @@
1
+ <h1>Edit Export</h1>
2
+
3
+ <%= render :partial => 'form' %>
4
+
5
+ <p>
6
+ <%= link_to_cancel @export %>
7
+ </p>
@@ -0,0 +1,9 @@
1
+ <table class='series'>
2
+ <caption>Export Filters</caption>
3
+ <tr>
4
+ <th>Field</th>
5
+ <th>Value</th>
6
+ <th class='action_icons'>&nbsp;</th>
7
+ </tr>
8
+ <%= render :partial => @export.export_filters %>
9
+ </table>
@@ -0,0 +1,25 @@
1
+ <div id="rexport">
2
+ <%= form_for(@export) do |f| %>
3
+ <%= f.error_messages %>
4
+
5
+ <div class="export_base_info">
6
+ <%= f.label :name %>
7
+ <%= f.text_field :name %>
8
+ </div>
9
+ <div class="export_base_info">
10
+ <%= f.label :description %>
11
+ <%= f.text_area :description %>
12
+ </div>
13
+
14
+ <%= render :partial => 'local_form', :locals => { :form => f } %>
15
+
16
+ <h3>Export Items</h3>
17
+ <%= render :partial => 'rexport_model', :collection => @export.rexport_models %>
18
+
19
+ <%= f.hidden_field :model_name %>
20
+
21
+ <div>
22
+ <%= f.submit 'Save Export' %>
23
+ </div>
24
+ <% end %>
25
+ </div>
@@ -0,0 +1 @@
1
+ <!-- override to add additional fields -->
@@ -0,0 +1,17 @@
1
+ <table class='series'>
2
+ <caption><%= rexport_model.name %> (<%= rexport_model.path %>)</caption>
3
+ <tr>
4
+ <th>Export</th>
5
+ <th>Data Field</th>
6
+ <th>Filter Value</th>
7
+ </tr>
8
+ <% for field in rexport_model.rexport_fields_array %>
9
+ <tr class="<%= cycle('odd','even') %>">
10
+ <td><%= check_box_tag "export[rexport_fields][#{rexport_model.field_path(field.name)}]", 1, @export.has_rexport_field?(rexport_model.field_path(field.name)) %></td>
11
+ <td class="row_title"><%= field.name.titleize %></td>
12
+ <td class='row_title'>
13
+ <%= filter_value_field(rexport_model, field) %>
14
+ </td>
15
+ </tr>
16
+ <% end %>
17
+ </table>
@@ -0,0 +1,53 @@
1
+ <h1><%= @export.name %></h1>
2
+ <div id="custom_export_options">
3
+ <h4>Options</h4>
4
+ <ul>
5
+ <li><%= link_to("#{image_tag('icon_edit.gif')} Edit".html_safe, edit_export_path(@export)) if @export.modifiable? %></li>
6
+ <li><%= link_to "#{image_tag('icon_export.png')} Export".html_safe, export_path(@export, :format => :csv) %></li>
7
+ <li><%= link_to "#{image_tag('icon_copy.png')} Copy".html_safe, exports_path(:original_export_id => @export.id), :method => :post %></li>
8
+ </ul>
9
+ </div>
10
+ <div class="show_export_info">
11
+ <p>
12
+ <label>Category:</label>
13
+ <%= @export.model_name %>
14
+ </p>
15
+ </div>
16
+ <div class="show_export_info">
17
+ <p>
18
+ <label>Description:</label>
19
+ </p>
20
+ <%= simple_format @export.description %>
21
+ </div>
22
+
23
+ <table>
24
+ <caption>Export Items</caption>
25
+ <thead>
26
+ <tr>
27
+ <th>Name</th>
28
+ <th>Export Field</th>
29
+ <th class='action_icons'>&nbsp;</th>
30
+ </tr>
31
+ </thead>
32
+ <%= content_tag :tbody, {:id => 'export_items'}.merge(@export.modifiable? ? {:class => 'sortable', 'data-url' => export_item_sorting_path} : {}) do %>
33
+ <%= render :partial => @export.export_items.ordered %>
34
+ <% end %>
35
+ </table>
36
+
37
+ <%= content_tag(:p, 'Drag and drop the rows in the table above to re-order the export data left to right in the output (see sample below).', :class => 'instructions') if @export.modifiable? %>
38
+
39
+ <%= render(:partial => 'filters') unless @export.export_filters.blank? %>
40
+
41
+ <div class='scrolling'>
42
+ <table>
43
+ <caption>Sample Output (first <%= Rexport::SAMPLE_SIZE %> records)</caption>
44
+ <tr>
45
+ <%= (@export.header.map {|heading| content_tag(:th, heading)} * '').html_safe %>
46
+ </tr>
47
+ <% for record in @export.sample_records %>
48
+ <tr class="<%= cycle('odd','even') %>">
49
+ <%= (record.map { |item| content_tag(:td, item) } * '').html_safe %>
50
+ </tr>
51
+ <% end %>
52
+ </table>
53
+ </div>
@@ -0,0 +1 @@
1
+ <%= render :partial => 'edit' %>
@@ -0,0 +1,33 @@
1
+ <%= form_for Export.new, :url => new_export_path, :html => {:method => :get} do |f| %>
2
+ <fieldset>
3
+ <legend>Create New Export</legend>
4
+ <div class='dropdown'>
5
+ <%= f.select :model_name, Export.models %>
6
+ <%= f.submit 'Create' %>
7
+ </div>
8
+ </fieldset>
9
+ <% end %>
10
+
11
+ <table>
12
+ <caption>Export List</caption>
13
+ <tr>
14
+ <th>Name</th>
15
+ <th>Description</th>
16
+ <th>Created</th>
17
+ <th class='action_icons wider'>&nbsp;</th>
18
+ </tr>
19
+
20
+ <% for export in @exports %>
21
+ <tr class="<%= cycle('odd', 'even') %>">
22
+ <td class="row_title"><%= link_to export.full_name, export %></td>
23
+ <td class='description'><%= export.description %></td>
24
+ <td><%= print_date export.created_at %></td>
25
+ <td class="table_icons">
26
+ <%= link_to_export export_path(export, :format => :csv), :text => false %>
27
+ <%= link_to_show export, :text => false %>
28
+ <%= link_to(image_tag('icon_edit.gif'), edit_export_path(export), :title => 'Edit') if export.modifiable? %>
29
+ <%= link_to_delete(export, :text => false) if export.modifiable? %>
30
+ </td>
31
+ </tr>
32
+ <% end %>
33
+ </table>
@@ -0,0 +1,7 @@
1
+ <h1>New <%= @export.model_name %> Export</h1>
2
+
3
+ <%= render :partial => 'form' %>
4
+
5
+ <div>
6
+ <%= link_to_cancel exports_path %>
7
+ </div>
@@ -0,0 +1 @@
1
+ <%= render :partial => 'show' %>
data/config/routes.rb ADDED
@@ -0,0 +1,11 @@
1
+ Rails.application.routes.draw do
2
+ # singleton resources
3
+ resource :export_item_sorting, :only => [:update]
4
+
5
+ # collection resources
6
+ resources :export_items, :only => [:edit, :update, :destroy]
7
+ resources :export_filters, :only => [:edit, :update, :destroy]
8
+ resources :exports do
9
+ resources :export_filters, :only => [:new]
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ class CreateExportTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "export_filters", :force => true do |t|
4
+ t.integer "export_id"
5
+ t.string "field"
6
+ t.string "value"
7
+ t.datetime "created_at"
8
+ t.datetime "updated_at"
9
+ end
10
+
11
+ create_table "export_items", :force => true do |t|
12
+ t.integer "export_id"
13
+ t.integer "position"
14
+ t.string "name"
15
+ t.string "rexport_field"
16
+ t.datetime "created_at"
17
+ t.datetime "updated_at"
18
+ end
19
+
20
+ create_table "exports", :force => true do |t|
21
+ t.string "name"
22
+ t.string "model_name"
23
+ t.text "description"
24
+ t.datetime "created_at"
25
+ t.datetime "updated_at"
26
+ end
27
+ end
28
+
29
+ def self.down
30
+ drop_table :export_filters
31
+ drop_table :export_items
32
+ drop_table :exports
33
+ end
34
+ end
data/lib/rexport.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'rexport/data_fields'
2
+ require 'rexport/export_filter_methods'
3
+ require 'rexport/export_filters_controller_methods'
4
+ require 'rexport/export_item_methods'
5
+ require 'rexport/export_item_sortings_controller_methods'
6
+ require 'rexport/export_items_controller_methods'
7
+ require 'rexport/export_methods'
8
+ require 'rexport/exports_controller_methods'
9
+ require 'rexport/tree_node'
10
+
11
+ module Rexport
12
+
13
+ class Engine < ::Rails::Engine
14
+ config.paths['app/views'] << File.join(File.dirname(__FILE__),'../app/views')
15
+ end
16
+
17
+ end
@@ -0,0 +1,152 @@
1
+ module Rexport #:nodoc:
2
+
3
+ # Stores the name and method of the export data item
4
+ class DataField
5
+ include Comparable
6
+ attr_accessor :name, :method, :type
7
+
8
+ def initialize(name, options = {})
9
+ self.name = name.to_s
10
+ self.method = options[:method].blank? ? self.name : options[:method].to_s
11
+ self.type = options[:type]
12
+ end
13
+
14
+ def <=>(rf)
15
+ self.name <=> rf.name
16
+ end
17
+ end
18
+
19
+ module DataFields
20
+ def self.included( base )
21
+ base.extend( ClassMethods )
22
+ base.class_eval do
23
+ include InstanceMethods
24
+ class << self
25
+ alias_method_chain :reset_column_information, :rexport_reset
26
+ end
27
+ end
28
+ end
29
+
30
+ module ClassMethods
31
+ # Returns hash of exportable data items
32
+ def rexport_fields
33
+ unless @rexport_fields
34
+ @rexport_fields = HashWithIndifferentAccess.new
35
+ initialize_rexport_fields
36
+ end
37
+ @rexport_fields
38
+ end
39
+
40
+ # Returns sorted array of rexport DataFields
41
+ def rexport_fields_array
42
+ rexport_fields.merge(dynamic_rexport_fields).values.sort
43
+ end
44
+
45
+ # Adds a data item to rexport_fields
46
+ def add_rexport_field(name, options = {})
47
+ rexport_fields[name.to_s] = DataField.new(name, options)
48
+ end
49
+
50
+ # Adds associated methods to rexport_fields
51
+ # :associations - an association or arrary of associations
52
+ # :methods - a method or array of methods
53
+ # :filter - if true will send :type => :association to add_report_field
54
+ def add_association_methods(options = {})
55
+ options.stringify_keys!
56
+ options.assert_valid_keys(%w(associations methods filter))
57
+
58
+ methods = options.reverse_merge('methods' => 'name')['methods']
59
+ methods = [methods] if methods.kind_of?(String)
60
+
61
+ associations = options['associations']
62
+ associations = [associations] if associations.kind_of?(String)
63
+
64
+ type = options['filter'] ? :association : nil
65
+
66
+ associations.each do |association|
67
+ methods.each do |method|
68
+ add_rexport_field("#{association}_#{method}", :method => "#{association}.#{method}", :type => type)
69
+ end
70
+ end
71
+ end
72
+
73
+ # Removes files from rexport_fields
74
+ # useful to remove content columns you don't want included in exports
75
+ def remove_rexport_fields(*fields)
76
+ fields.flatten.each {|field| rexport_fields.delete(field.to_s)}
77
+ end
78
+
79
+ # Returns an array of export methods corresponding with field_names
80
+ def get_rexport_methods(*field_names)
81
+ field_names.flatten.map do |f|
82
+ begin
83
+ components = f.to_s.split('.')
84
+ field_name = components.pop
85
+ components.push(get_klass_from_associations(components).get_rexport_method(field_name)) * '.'
86
+ rescue NoMethodError
87
+ 'undefined_rexport_field'
88
+ end
89
+ end
90
+ end
91
+
92
+ # Returns the associated class by following the associations
93
+ def get_klass_from_associations(*associations)
94
+ associations.flatten!
95
+ return self if associations.empty?
96
+ reflect_on_association(associations.shift.to_sym).klass.get_klass_from_associations(associations)
97
+ end
98
+
99
+ # Returns the export method for a given field_name
100
+ def get_rexport_method(field_name)
101
+ raise NoMethodError unless rexport_fields[field_name] or dynamic_rexport_fields[field_name]
102
+ if rexport_fields[field_name]
103
+ rexport_fields[field_name].method
104
+ else
105
+ dynamic_rexport_fields[field_name].method
106
+ end
107
+ end
108
+
109
+ def reset_column_information_with_rexport_reset
110
+ reset_column_information_without_rexport_reset
111
+ @rexport_fields = nil
112
+ end
113
+
114
+ private
115
+
116
+ # Adds content columns and columns ending in "_count" to rexport_fields, includes callback initialize_local_rexport_fields
117
+ # for client defined initialization
118
+ def initialize_rexport_fields
119
+ (content_columns + columns.select {|c| c.name =~ /_count$/}).each do |f|
120
+ add_rexport_field(f.name, :type => f.type)
121
+ end
122
+ initialize_local_rexport_fields if respond_to?(:initialize_local_rexport_fields)
123
+ end
124
+
125
+ def dynamic_rexport_fields
126
+ respond_to?(:initialize_dynamic_rexport_fields) ? initialize_dynamic_rexport_fields : {}
127
+ end
128
+ end
129
+
130
+ module InstanceMethods
131
+ # Return an array of formatted export for the passed methods
132
+ def export(*methods)
133
+ methods.flatten.map do |method|
134
+ case value = (eval("self.#{method}", binding) rescue nil)
135
+ when Date, Time
136
+ value.strftime("%m/%d/%y")
137
+ when TrueClass
138
+ 'Y'
139
+ when FalseClass
140
+ 'N'
141
+ else value.to_s
142
+ end
143
+ end
144
+ end
145
+
146
+ # Returns string indicating this field is undefined
147
+ def undefined_rexport_field
148
+ 'UNDEFINED EXPORT FIELD'
149
+ end
150
+ end
151
+ end
152
+ end