rexport 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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