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.
@@ -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
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in easy_export.gemspec
4
+ gemspec
@@ -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.
@@ -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
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module EasyExport
2
+ VERSION = "0.0.1"
3
+ end
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: []