easy_export 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +70 -0
- data/Rakefile +2 -0
- data/easy_export.gemspec +25 -0
- data/lib/easy_export.rb +142 -0
- data/lib/easy_export/version.rb +3 -0
- metadata +96 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 1b4fc3404829b1479ae77339a3378a0b55b830c8
|
|
4
|
+
data.tar.gz: d058995fca33aedb12d97550afed718cab82d422
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 67fb25822011bdf24225804711ea875a5a2aef276b74a1e63f53e9e03bca41031a4dfc6ea7cfb1798584c530b2e6f94e7137fbb505377a14a7464847d12fc056
|
|
7
|
+
data.tar.gz: 2d658989bc1d9e29a380069761060c64284beef526f778f7ff122a5949ba6b2116310d0fa532be1d7a9b01f41e6c3ee1e8fbbc2e1c470471605af2d01d2fb5f8
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2015 Diego Salazar
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# EasyExport
|
|
2
|
+
|
|
3
|
+
Export ActiveModels to CSV by declaring headers and fields in your model with the `exportable` class method and block.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'easy_export'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
$ bundle
|
|
16
|
+
|
|
17
|
+
Or install it yourself as:
|
|
18
|
+
|
|
19
|
+
$ gem install easy_export
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
In a model, add the `exportable` declaration:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
class User < ActiveRecord::Base
|
|
27
|
+
exportable do
|
|
28
|
+
scope -> { User.all }
|
|
29
|
+
fields [
|
|
30
|
+
['Header 1', -> { value to return }],
|
|
31
|
+
['Header 2', :method_name],
|
|
32
|
+
['Header 3', 'static value'], ...
|
|
33
|
+
]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Now, use the `Exporter` to get the CSV data:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
exporter = Exportable::Exporter.new params[:export]
|
|
42
|
+
|
|
43
|
+
exporter.data # The CSV data
|
|
44
|
+
exporter.file_type # 'text/csv'
|
|
45
|
+
exporter.file_name # 'users-<timestamp>.csv'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
With those you can initiate a download from a controller:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
send_data exporter.data, {
|
|
52
|
+
filetype: exporter.file_type,
|
|
53
|
+
filename: exporter.file_name,
|
|
54
|
+
disposition: 'attachment'
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Todo
|
|
59
|
+
|
|
60
|
+
1. Support more export types: XML, JSON, YML
|
|
61
|
+
2. Add method to write the data to a file
|
|
62
|
+
3. Clean up the way `fields` are declared.
|
|
63
|
+
|
|
64
|
+
## Contributing
|
|
65
|
+
|
|
66
|
+
1. Fork it ( https://github.com/[my-github-username]/easy_export/fork )
|
|
67
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
68
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
69
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
70
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/easy_export.gemspec
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'easy_export/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "easy_export"
|
|
8
|
+
spec.version = EasyExport::VERSION
|
|
9
|
+
spec.authors = ["Diego Salazar"]
|
|
10
|
+
spec.email = ["diego@greyrobot.com"]
|
|
11
|
+
spec.summary = %q{Export ActiveModels to CSV by declaring headers and fields in your model with the `exportable` class method and block.}
|
|
12
|
+
spec.description = %q{Export ActiveModels to CSV by declaring headers and fields in your model with the `exportable` class method and block.}
|
|
13
|
+
spec.homepage = ""
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_dependency "active_support"
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
25
|
+
end
|
data/lib/easy_export.rb
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
require "easy_export/version"
|
|
2
|
+
require 'active_support'
|
|
3
|
+
|
|
4
|
+
module EasyExport
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
# Declare this method in your model class to define the export configuration.
|
|
9
|
+
#
|
|
10
|
+
# The block will be executed in the context of the ExportConfig, e.g:
|
|
11
|
+
#
|
|
12
|
+
# exportable do
|
|
13
|
+
# scope -> { ['some records', ...] }
|
|
14
|
+
# fields [
|
|
15
|
+
# ['Header 1', -> { value to return }],
|
|
16
|
+
# ['Header 2', :method_name],
|
|
17
|
+
# ['Header 3', 'static value'], ...
|
|
18
|
+
# ]
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# scope: an object that responds to #call and returns a collection of instances
|
|
22
|
+
# fields: an array of tuples where the 1st element is the Header name
|
|
23
|
+
# and the 2nd is a proc, symbol, or static value to be instance
|
|
24
|
+
# exec'ed, called as a method on the instance, or just returned, respectively.
|
|
25
|
+
#
|
|
26
|
+
def exportable(&block)
|
|
27
|
+
@export_config ||= ExportConfig.new
|
|
28
|
+
@export_config.partial = name.demodulize.underscore.pluralize
|
|
29
|
+
@export_config.instance_exec &block
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def export_partial; @export_config.partial end
|
|
33
|
+
def export_scope; @export_config.scope end
|
|
34
|
+
def export_fields; @export_config.fields end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class ExportConfig
|
|
38
|
+
attr_accessor :partial
|
|
39
|
+
|
|
40
|
+
def scope(val = nil)
|
|
41
|
+
val.nil? ? @scope : @scope = val
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def fields(val = nil)
|
|
45
|
+
val.nil? ? @fields : @fields = build_fields(val)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# Providing fields as an array let's us maintain the ordering
|
|
51
|
+
def build_fields(fields)
|
|
52
|
+
raise ArgumentError, "fields must be an array" unless fields.is_a? Array
|
|
53
|
+
|
|
54
|
+
ActiveSupport::OrderedHash.new.tap do |hash|
|
|
55
|
+
fields.each do |header, value_proc|
|
|
56
|
+
hash[header] = value_proc
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class Exporter
|
|
63
|
+
require 'csv'
|
|
64
|
+
|
|
65
|
+
# Instantiate an Exporter that will convert a collection of models into
|
|
66
|
+
# a CSV string. The model needs to be setup with `exportable` class method.
|
|
67
|
+
#
|
|
68
|
+
# @options:
|
|
69
|
+
# model: string name of the model class used to fetch instances to convert.
|
|
70
|
+
# filter: a string that can be used by the @scope to further filter models
|
|
71
|
+
# ...any other args needed in the options passed to the @scope.
|
|
72
|
+
#
|
|
73
|
+
# @model: the model class.
|
|
74
|
+
# @scope: a proc or object that responds to #call and takes the @options hash
|
|
75
|
+
# and returns a scoped collection of instances of @model.
|
|
76
|
+
# @fields: an array of 2 element arrays that represent the header and method
|
|
77
|
+
# to call on the model to retrieve the value for that column.
|
|
78
|
+
# @header: the first element of every array in @fields
|
|
79
|
+
#
|
|
80
|
+
def initialize(options = {})
|
|
81
|
+
@options = options
|
|
82
|
+
@model = options[:model].constantize
|
|
83
|
+
@scope = @model.export_scope
|
|
84
|
+
@fields = @model.export_fields
|
|
85
|
+
@header = @fields.keys
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def data
|
|
89
|
+
CSV.generate do |csv|
|
|
90
|
+
csv << @header
|
|
91
|
+
|
|
92
|
+
scoped_models.each do |model|
|
|
93
|
+
csv << generate_row(model)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def file_name
|
|
99
|
+
timestamp = I18n.l(Time.zone.now, format: :short_date_only).parameterize
|
|
100
|
+
model_name = @model.name.demodulize.pluralize
|
|
101
|
+
"#{model_name}-#{timestamp}.csv"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def file_type
|
|
105
|
+
'text/csv'
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
protected
|
|
109
|
+
|
|
110
|
+
def scoped_models
|
|
111
|
+
@scope.call @options
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Generate an array representing a CSV row by iterating over @fields
|
|
115
|
+
# and using the 2nd item in each array as a value getter. It can be
|
|
116
|
+
# either a proc that is called in the context of the model, a symbol
|
|
117
|
+
# representing a method to call on the model, or a static value.
|
|
118
|
+
def generate_row(model)
|
|
119
|
+
@fields.map do |_, value_proc|
|
|
120
|
+
if value_proc.is_a? Proc
|
|
121
|
+
begin
|
|
122
|
+
model.instance_exec &value_proc
|
|
123
|
+
rescue NameError => e
|
|
124
|
+
# This happens when the model is a GroupSession hash that was returned by the @scope
|
|
125
|
+
# when the user selects GroupSession in the calendar filters
|
|
126
|
+
# TODO: Have the AppointmentFilter convert those
|
|
127
|
+
# hashes into AR like objects that respond to all
|
|
128
|
+
# the same methods Appointments do.
|
|
129
|
+
# For now, just put an error in this field.
|
|
130
|
+
"Error getting field value"
|
|
131
|
+
end
|
|
132
|
+
elsif model.respond_to? value_proc
|
|
133
|
+
model.send value_proc
|
|
134
|
+
else
|
|
135
|
+
value_proc
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
ActiveRecord::Base.send :include, EasyExport
|
metadata
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: easy_export
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Diego Salazar
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-02-06 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: active_support
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.7'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.7'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '10.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '10.0'
|
|
55
|
+
description: Export ActiveModels to CSV by declaring headers and fields in your model
|
|
56
|
+
with the `exportable` class method and block.
|
|
57
|
+
email:
|
|
58
|
+
- diego@greyrobot.com
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- ".gitignore"
|
|
64
|
+
- Gemfile
|
|
65
|
+
- LICENSE.txt
|
|
66
|
+
- README.md
|
|
67
|
+
- Rakefile
|
|
68
|
+
- easy_export.gemspec
|
|
69
|
+
- lib/easy_export.rb
|
|
70
|
+
- lib/easy_export/version.rb
|
|
71
|
+
homepage: ''
|
|
72
|
+
licenses:
|
|
73
|
+
- MIT
|
|
74
|
+
metadata: {}
|
|
75
|
+
post_install_message:
|
|
76
|
+
rdoc_options: []
|
|
77
|
+
require_paths:
|
|
78
|
+
- lib
|
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '0'
|
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
requirements: []
|
|
90
|
+
rubyforge_project:
|
|
91
|
+
rubygems_version: 2.4.3
|
|
92
|
+
signing_key:
|
|
93
|
+
specification_version: 4
|
|
94
|
+
summary: Export ActiveModels to CSV by declaring headers and fields in your model
|
|
95
|
+
with the `exportable` class method and block.
|
|
96
|
+
test_files: []
|