active_export 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *.gem
2
+ .bundle
3
+ .config
4
+ .yardoc
5
+ _yardoc
6
+ doc/
7
+ coverage
8
+ tmp
9
+ log/*
10
+ Gemfile.lock
data/.yardopts ADDED
@@ -0,0 +1,7 @@
1
+ lib/**/*.rb
2
+ --protected
3
+ --no-private
4
+ -
5
+ README.rdoc
6
+ CHANGELOG.md
7
+ docs/**/*.md
data/Gemfile ADDED
@@ -0,0 +1,27 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in active_export.gemspec
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem 'rake', '~> 0.9.2.2', :require => false
8
+ gem 'rails', ">= #{ENV['RAILS'] || '3.0.0'}"
9
+
10
+ gem 'yard'
11
+ gem 'rdiscount'
12
+
13
+ gem 'tapp', :git => 'git://github.com/esminc/tapp.git'
14
+
15
+ gem 'sqlite3'
16
+ gem 'rspec-rails'
17
+ gem 'factory_girl_rails'
18
+ gem 'database_cleaner'
19
+ gem 'guard'
20
+ gem 'guard-rspec'
21
+ gem 'fuubar'
22
+
23
+ gem 'libnotify', :require => false
24
+ gem 'rb-inotify', :require => false
25
+ gem 'rb-fsevent', :require => false
26
+ gem 'growl', :require => false
27
+ end
data/Guardfile ADDED
@@ -0,0 +1,10 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2, :cli => "--color --format Fuubar --profile", keep_failed: false, all_on_start: false, all_after_pass: false do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/active_export/(.+)\.rb$}) { |m| "spec/active_export/#{m[1]}_spec.rb" }
7
+ watch('lib/active_export.rb') { "spec" }
8
+ watch('spec/spec_helper.rb') { "spec" }
9
+ end
10
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 kengos
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,180 @@
1
+ # ActiveExport
2
+
3
+ Export to csv from ActiveRecord or others
4
+
5
+ You do not need to write the dirty code to output the csv in your controller, model or others.
6
+
7
+ In your controller:
8
+
9
+ ````ruby
10
+ ActiveExport::Csv.export(Book.all, source_name, namespace)
11
+
12
+ # it means
13
+ CSV.generate do |csv|
14
+ csv << ['Title', 'Author', 'Price(in Tax)', 'Published Date']
15
+ Book.all.each do |book|
16
+ csv << [book.name, (book.author.try(:name) || ''), book.price, book.created_at.strftime('%Y%m%d')]
17
+ end
18
+ end
19
+ end
20
+ ````
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'active_export'
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install active_export
35
+
36
+ ## Usage
37
+
38
+ Add initalizers `active_export.rb`
39
+
40
+ Create `active_export.yml` And write csv export method
41
+
42
+ [YAML file format][yaml-file-format]
43
+
44
+ Use `ActiveExport::Csv.export(data, source_name, namespace)` in your controller or others.
45
+
46
+ ## Example
47
+
48
+ ActiveRecord:
49
+
50
+ ````ruby
51
+ class Book < ActiveRecord::Base
52
+ belongs_to :author
53
+ end
54
+
55
+ class Author < ActiveRecord::Base
56
+ end
57
+ ````
58
+
59
+ Book records:
60
+
61
+ | id | name | author_id | price | created_at |
62
+ |:--:|:----:|:---------:|:-----:|:----------:|
63
+ | 1 | Ruby | 1 | 50 | 2012/08/01 00:00:00 UTC |
64
+ | 2 | Java | 2 | 30 | 2012/08/02 00:00:00 UTC |
65
+
66
+ Author records:
67
+
68
+ | id | name |
69
+ |:--:|:-----:|
70
+ | 1 | Bob |
71
+ | 2 | Alice |
72
+
73
+ `en.yml`:
74
+
75
+ <pre>
76
+ activerecord:
77
+ attributes:
78
+ book:
79
+ name: 'Title'
80
+ price: 'Price(in Tax)'
81
+ created_at: 'Published Date'
82
+ author:
83
+ name: 'Author'
84
+ </pre>
85
+
86
+ `config/initializers/active_export.rb`:
87
+
88
+ ````ruby
89
+ ActiveExportconfigure do |config|
90
+ config.sources = { default: Rails.root.join('config', 'active_export.yml') }
91
+ ## option fields
92
+ # config.default_csv_optoins = { col_sep: ',', row_sep: "\n", force_quotes: true }
93
+ # config.always_reload = false # default
94
+ # config.no_source_raise_error = false # default
95
+ end
96
+ ````
97
+
98
+ `config/active_export.yml`:
99
+
100
+ ````
101
+ book:
102
+ label_prefix: 'book'
103
+ methods:
104
+ - name
105
+ - author.name
106
+ - price
107
+ - created_at: creaetd_at.strftime('%Y/%m/%d')
108
+ ````
109
+
110
+ In your controller or others:
111
+
112
+ ````ruby
113
+ ActiveExport::Csv.export(Book.all, :default, :book)
114
+ # => CSV string
115
+ # "Title","Author","Price(in Tax)","Published Date"
116
+ # "Ruby","Bob","50","2012/08/01"
117
+ # "Java","Alice","20","2012/08/02"
118
+ ````
119
+
120
+ ## YAML file format
121
+
122
+ ```
123
+ [namespace]:
124
+ label_prefix: [label_prefix]
125
+ methods:
126
+ - [method_name]
127
+ - [label_name]: [method_name]
128
+ - ...
129
+ ```
130
+
131
+ ### Method_name examples
132
+
133
+ ```
134
+ book:
135
+ - "author.name" # call [instance].author.name
136
+ - "price > 0" # call [instance].price > 0 # => true or false
137
+ - "price.to_f / 2.0" # call [instance].price.to_f / 2.0
138
+ - "sprintf("%#b", price)" # call sprintf("%#b", [instance].price)
139
+ ```
140
+
141
+ ### I18n field priority
142
+
143
+ 1. `active_export.#{source_name}.#{namespace}.(label_prefix_)#{key}`
144
+ 2. `activerecord.attributes.(label_prefix.)#{key}`
145
+ 3. `activemodel.attributes.(label_prefix.)#{key}`
146
+ 4. `#{key.to_s.gsub(".", "_").humanize}`
147
+
148
+ ex)
149
+ <pre>
150
+ key ... author.name
151
+ label_prefix ... book
152
+ source_name ... default
153
+ namespace ... book_1
154
+
155
+ 1. `active_export.default.book_1.author_name`
156
+ 2. `activerecord.attributes.author.name`
157
+ 3. `activemode.attributes.author.name`
158
+ 4. `author_name".humanize # => Author name`
159
+ </pre>
160
+
161
+ ex2)
162
+ <pre>
163
+ key ... "name"
164
+ label_prefix ... "book"
165
+ source_name ... "default"
166
+ namespace ... "book_1"
167
+
168
+ 1. "active_export.default.book_1.book_name"
169
+ 2. "activerecord.attributes.book.name"
170
+ 3. "activemode.attributes.book.name"
171
+ 4. "book_name".humanize # => Book name
172
+ </pre>
173
+
174
+ ## Contributing
175
+
176
+ 1. Fork it
177
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
178
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
179
+ 4. Push to the branch (`git push origin my-new-feature`)
180
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ def cmd(command)
6
+ puts command
7
+ raise unless system command
8
+ end
9
+
10
+ # Import all our rake tasks
11
+ FileList['tasks/**/*.rake'].each { |task| import task }
12
+
13
+ require 'rspec/core'
14
+ require 'rspec/core/rake_task'
15
+ RSpec::Core::RakeTask.new(:spec) do |spec|
16
+ spec.pattern = FileList['spec/**/*_spec.rb']
17
+ end
18
+ # Run the specs
19
+ task :default => :spec
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/active_export/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["kengos"]
6
+ gem.email = ["kengo@kengos.jp"]
7
+ gem.description = %q{Export to CSV from ActiveRecord collections.}
8
+ gem.summary = %q{Export to CSV from ActiveRecord collections.}
9
+ gem.homepage = "https://github.com/kengos/active_export"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+
13
+ gem.add_dependency("activesupport", ">= 3.0.0")
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "active_export"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = ActiveExport::VERSION
19
+ end
@@ -0,0 +1,101 @@
1
+ # coding: utf-8
2
+
3
+ require 'i18n'
4
+ require 'active_support'
5
+
6
+ module ActiveExport
7
+ class Base
8
+ attr_accessor :source_name, :namespace, :label_prefix, :source, :label_keys, :eval_methods
9
+ attr_reader :config
10
+ def initialize(source_name, namespace, options = {})
11
+ @source_name = source_name.to_sym
12
+ @namespace = namespace.to_sym
13
+ @config = ::ActiveExport.configuration
14
+ @label_keys = options.has_key?(:label_keys) ? options[:label_keys] : nil
15
+ @eval_methods = options.has_key?(:eval_methods) ? options[:eval_methods] : nil
16
+ @label_prefix = options.has_key?(:label_prefix) ? options[:label_prefix] : nil
17
+ end
18
+
19
+ class << self
20
+ def translate(key, scope = [])
21
+ defaults = [
22
+ :"active_export.#{scope.join('.')}.#{key.to_s.gsub('.', '_')}",
23
+ :"activerecord.attributes.#{key}",
24
+ :"activemodel.attributes.#{key}",
25
+ key.to_s.gsub('.', '_').humanize
26
+ ]
27
+ I18n.translate(defaults.shift, default: defaults)
28
+ end
29
+
30
+ # @param [Array] methods
31
+ # @return [Array]
32
+ def build_label_keys_and_eval_methods(methods)
33
+ label_keys = []
34
+ eval_methods = []
35
+ methods.each do |f|
36
+ if f.is_a?(Hash)
37
+ label_keys << f.keys.first
38
+ eval_methods << f.values.first
39
+ else
40
+ label_keys << f
41
+ eval_methods << f
42
+ end
43
+ end
44
+ return label_keys, eval_methods
45
+ end
46
+ end
47
+
48
+ # Convert value for export string
49
+ # @todo refactor me
50
+ def convert(value)
51
+ if value.nil?
52
+ translate(:nil, config.default_value_label_scope)
53
+ elsif value == ''
54
+ translate(:blank, config.default_value_label_scope)
55
+ elsif value == true
56
+ translate(:true, config.default_value_label_scope)
57
+ elsif value == false
58
+ translate(:false, config.default_value_label_scope)
59
+ else
60
+ value.to_s
61
+ end
62
+ end
63
+
64
+ def label_keys
65
+ build_label_keys_and_eval_methods! unless @label_keys
66
+ @label_keys
67
+ end
68
+
69
+ def eval_methods
70
+ build_label_keys_and_eval_methods! unless @eval_methods
71
+ @eval_methods
72
+ end
73
+
74
+ def label_prefix
75
+ @label_prefix ||= source[:label_prefix]
76
+ end
77
+
78
+ def default_scope
79
+ [self.source_name, self.namespace]
80
+ end
81
+
82
+ def key_name(key)
83
+ key.to_s.include?(".") ? key.to_s : "#{label_prefix}.#{key}"
84
+ end
85
+
86
+ def build_label_keys_and_eval_methods!
87
+ @label_keys, @eval_methods = self.class.build_label_keys_and_eval_methods(source[:methods])
88
+ end
89
+
90
+ def source
91
+ @source ||= ::ActiveExport[self.source_name][self.namespace]
92
+ rescue => e
93
+ raise e if config.no_source_raise_error = true
94
+ return {}
95
+ end
96
+
97
+ def translate(key, scope = nil)
98
+ self.class.translate(key, scope || default_scope)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+
3
+ module ActiveExport
4
+ class Configuration
5
+ attr_accessor :sources
6
+ attr_accessor :default_csv_options
7
+ attr_accessor :always_reload
8
+ attr_accessor :default_value_label_scope
9
+ attr_accessor :no_source_raise_error
10
+
11
+ def initialize
12
+ @sources = {}
13
+ @default_csv_options = { col_sep: ',', row_sep: "\n", force_quotes: true }
14
+ @always_reload = false
15
+ @default_value_label_scope = [:default_value_labels]
16
+ @no_source_raise_error = false
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,48 @@
1
+ # coding: utf-8
2
+
3
+ require 'csv'
4
+
5
+ module ActiveExport
6
+ class Csv < ::ActiveExport::Base
7
+ # @param [Array, ActiveRecord::Relation] data
8
+ # @param [Symbol, String] source
9
+ # @param [Symobl, String] namespace
10
+ # @param [Hash] options ({})
11
+ # @option options [Array] :eval_methods
12
+ # @option options [Array] :label_keys
13
+ # @option options [String] :label_prefix
14
+ # @option options [Hash] :csv_options (see http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV.html)
15
+ # @exmaple
16
+ # AcriveExport::Csv.export(data, :source, :namespace)
17
+ def self.export(data, source, namespace, options = {})
18
+ new(source, namespace, options).export(data, options)
19
+ end
20
+
21
+ def export(data, options = {})
22
+ return '' if data.length <= 0 && eval_methods.nil?
23
+ csv_options = self.config.default_csv_options.merge( options[:csv_options] || {} )
24
+
25
+ each_method_name = data.respond_to?(:find_each) ? 'find_each' : 'each'
26
+ # 1.9.2
27
+ CSV.generate(csv_options) do |csv|
28
+ csv << generate_header
29
+ data.send(each_method_name) do |f|
30
+ csv << generate_value(f)
31
+ end
32
+ end
33
+ end
34
+
35
+ def generate_header
36
+ self.label_keys.inject([]) {|result, key|
37
+ result << translate(key_name(key))
38
+ }
39
+ end
40
+
41
+ def generate_value(row)
42
+ self.eval_methods.inject([]){|result, f|
43
+ v = row.send(:eval, f) rescue nil
44
+ result << convert(v)
45
+ }
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveExport
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,76 @@
1
+ require "active_export/version"
2
+ require 'active_export/configuration'
3
+ require 'yaml'
4
+ require 'erb'
5
+
6
+ module ActiveExport
7
+ autoload :Base, 'active_export/base'
8
+ autoload :Csv, 'active_export/csv'
9
+
10
+ class << self
11
+ # @example
12
+ # ActiveExportconfigure do |config|
13
+ # # ActiveExport export configuration files.
14
+ # config.sources = { default: Rails.root.join('config', 'active_export.yml') }
15
+ #
16
+ # # see CSV.new options
17
+ # config.default_csv_optoins = { col_sep: ',', row_sep: "\n", force_quotes: true }
18
+ #
19
+ # # if set 'true', ActiveExport no cached yml data. Every time load yml file.
20
+ # # if set 'false', ActiveExport cached yml data.
21
+ # config.always_reload = true # default false
22
+ #
23
+ # # if set 'true', not found sources[:source_name] to raise error
24
+ # config.no_source_raise_error = false # default
25
+ # end
26
+ def configure
27
+ yield configuration
28
+ end
29
+
30
+ # Accessor for ActiveExport::Configuration
31
+ def configuration
32
+ @configuration ||= Configuration.new
33
+ end
34
+ alias :config :configuration
35
+
36
+ def [](key)
37
+ source(key)
38
+ end
39
+
40
+ def clear!
41
+ @source = {}
42
+ true
43
+ end
44
+
45
+ def load!
46
+ config.sources.each {|f| source(f) }
47
+ true
48
+ end
49
+
50
+ def reload!
51
+ clear!
52
+ load!
53
+ end
54
+
55
+ def source(key)
56
+ if @configuration.always_reload
57
+ load!(key)
58
+ else
59
+ @sources ||= {}
60
+ @sources[key] ||= load!(key)
61
+ end
62
+ end
63
+
64
+ def include_source?(key)
65
+ @configuration.sources.has_key?(key)
66
+ end
67
+
68
+ def load!(key)
69
+ if include_source?(key)
70
+ ::ActiveSupport::HashWithIndifferentAccess.new(YAML.load(ERB.new(open(@configuration.sources[key]).read).result).to_hash)
71
+ else
72
+ raise "Missing '#{key}' in sources"
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,118 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActiveExport::Base do
6
+ before {
7
+ @default_locale = I18n.locale
8
+ I18n.locale = :en
9
+
10
+ ActiveExport.configure do |config|
11
+ config.sources = { default: fixture_file('csv_1.yml') }
12
+ end
13
+ }
14
+
15
+ after {
16
+ I18n.backend.reload!
17
+ I18n.locale = @default_locale
18
+ }
19
+
20
+ let(:active_export) { ActiveExport::Base.new('default', 'book_2') }
21
+ it { active_export.source_name = :default }
22
+ it { active_export.namespace = :book_2 }
23
+ it { active_export.config.should == ActiveExport.configuration }
24
+
25
+ context "with options" do
26
+ let(:active_export) { ActiveExport::Base.new('source', 'namespace', label_keys: %w(name), eval_methods: %w(price)) }
27
+ it { active_export.label_keys == %w(name) }
28
+ it { active_export.eval_methods == %w(price) }
29
+ end
30
+
31
+ it { active_export.label_keys.should == %w(name author.name price) }
32
+ it { active_export.eval_methods.should == ['name', 'author.name', '(price * 1.095).ceil.to_i'] }
33
+ it { active_export.label_prefix.should == 'book' }
34
+ it { active_export.default_scope == [:default, :book_2] }
35
+
36
+ it 'should not call build_label_keys_and_eval_methods!' do
37
+ active_export.label_keys
38
+ active_export.should_not_receive(:build_label_keys_and_eval_methods!)
39
+ active_export.label_keys
40
+ active_export.eval_methods
41
+ end
42
+
43
+ describe "#key_name" do
44
+ it { active_export.key_name('hoge').should eql 'book.hoge' }
45
+ it { active_export.key_name('author.name').should eql 'author.name' }
46
+ end
47
+
48
+ describe "#convert" do
49
+ before do
50
+ I18n.backend.store_translations :en, active_export: {
51
+ default_value_labels: { nil: 'Error', blank: 'Blank', true: 'Yes!', false: 'No!' }
52
+ }
53
+ end
54
+ it { active_export.convert(nil).should eql 'Error' }
55
+ it { active_export.convert('').should eql 'Blank' }
56
+ it { active_export.convert(true).should eql 'Yes!' }
57
+ it { active_export.convert(false).should eql 'No!' }
58
+ end
59
+
60
+ describe "#source" do
61
+ before {
62
+ active_export.source_name = :not_found
63
+ }
64
+ it { expect { active_export.source }.to raise_error RuntimeError }
65
+ end
66
+
67
+ describe ".build_label_keys_and_eval_methods" do
68
+ subject { ActiveExport::Base.build_label_keys_and_eval_methods(params) }
69
+
70
+ context "String" do
71
+ let(:params) { ["name"] }
72
+ it { should == [%w(name), %w(name)] }
73
+ end
74
+
75
+ context "Hash" do
76
+ let(:params) { [{"price"=>"price * 1.05"}] }
77
+ it { should == [%w(price), ["price * 1.05"]] }
78
+ end
79
+ end
80
+
81
+ describe ".translate" do
82
+ let(:i18n_key) { 'author.name' }
83
+ subject { ActiveExport::Base.translate('author.name', [:default, :book]) }
84
+
85
+ context "active_export" do
86
+ before do
87
+ I18n.backend.store_translations :en, active_export: {
88
+ default: {
89
+ book: { author_name: 'author_name' }
90
+ }
91
+ }
92
+ end
93
+ it { should == 'author_name' }
94
+ end
95
+
96
+ context "activerecord" do
97
+ before do
98
+ I18n.backend.store_translations :en, activerecord: {
99
+ attributes: { author: { name: 'AuthorName' } }
100
+ }
101
+ end
102
+ it { should == 'AuthorName' }
103
+ end
104
+
105
+ context "activemodel" do
106
+ before do
107
+ I18n.backend.store_translations :en, activemodel: {
108
+ attributes: { author: { name: 'Author_Name' } }
109
+ }
110
+ end
111
+ it { should == 'Author_Name' }
112
+ end
113
+
114
+ context "not found" do
115
+ it { should == 'Author name' }
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,98 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActiveExport::Csv do
6
+ before {
7
+ @default_locale = I18n.locale
8
+ I18n.locale = :en
9
+ }
10
+
11
+ after {
12
+ I18n.backend.reload!
13
+ I18n.locale = @default_locale
14
+ }
15
+
16
+ describe ".export" do
17
+ let(:author_1) { Author.create!(name: 'author_1') }
18
+ let(:author_2) { Author.create!(name: 'author_2') }
19
+ let!(:book_1) { Book.create!(name: 'book_1', author: author_1, price: 58) }
20
+ let!(:book_2) { Book.create!(name: 'book_2', author: author_2, price: 38) }
21
+
22
+ before {
23
+ ActiveExport.configure do |config|
24
+ config.sources = { default: fixture_file('csv_1.yml') }
25
+ config.default_csv_options = { col_sep: ',', row_sep: "\n", force_quotes: true }
26
+ end
27
+ }
28
+
29
+ context "no options" do
30
+ subject { ActiveExport::Csv.export(Book.order('id DESC').all, :default, :book_2) }
31
+ it {
32
+ should == <<-EOS
33
+ "Book name","Author name","Book price"
34
+ "book_2","author_2","42"
35
+ "book_1","author_1","64"
36
+ EOS
37
+ }
38
+ end
39
+
40
+ context "add some options" do
41
+ let(:csv_options) {
42
+ { force_quotes: false, col_sep: ':'}
43
+ }
44
+ subject { ActiveExport::Csv.export(Book.order('id DESC').all, :default, :book_1, csv_options: csv_options) }
45
+ it {
46
+ should == <<-EOS
47
+ Book name:Author name:Book price
48
+ book_2:author_2:38
49
+ book_1:author_1:58
50
+ EOS
51
+ }
52
+ end
53
+ end
54
+
55
+ describe ".generate_value" do
56
+ let(:author_1) { Author.create!(name: 'author_1') }
57
+ let!(:book_1) { Book.create!(name: 'book_1', author: author_1, price: 1000) }
58
+ let(:eval_methods) { ['name', "author.name", 'price', 'deleted_at', 'price > 0', 'price > 15000'] }
59
+ let(:csv_exporter) { ActiveExport::Csv.new(:default, :book_1, eval_methods: eval_methods) }
60
+
61
+ before {
62
+ I18n.backend.store_translations :en, active_export: {
63
+ default_value_labels: { nil: 'not found', blank: 'Blank', true: 'Yes!', false: 'No!' }
64
+ }
65
+ }
66
+ subject { csv_exporter.generate_value(book_1) }
67
+ it { should eql ['book_1', 'author_1', '1000', 'not found', 'Yes!', 'No!'] }
68
+ end
69
+
70
+ describe ".generate_header" do
71
+ let(:label_keys) { %w(name author.name price) }
72
+ let(:csv_exporter) { ActiveExport::Csv.new(:default, :book_1, label_keys: label_keys, label_prefix: 'book') }
73
+
74
+ subject { csv_exporter.generate_header }
75
+
76
+ context "no language file" do
77
+ it { should eql ['Book name', 'Author name', 'Book price'] }
78
+ end
79
+
80
+ context "translate" do
81
+ before do
82
+ I18n.backend.store_translations :en, activerecord: {
83
+ attributes: {
84
+ book: { name: 'name', price: 'Price(in tax)' },
85
+ author: { name: 'Author Name' }
86
+ }
87
+ }
88
+ I18n.backend.store_translations :en, active_export: {
89
+ default: {
90
+ book_1: { book_name: 'Title' }
91
+ }
92
+ }
93
+ end
94
+
95
+ it { should eql ['Title', 'Author Name', 'Price(in tax)'] }
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,8 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'RailsSupport' do
6
+ it { expect { Book.create!(name: 'test') }.to change(Book, :count).by(1) }
7
+ it { expect { FactoryGirl.create(:book) }.to change(Book, :count).by(1) }
8
+ end
@@ -0,0 +1,43 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActiveExport do
6
+ it 'should access sources' do
7
+ ActiveExport.configure do |config|
8
+ config.sources = { :default => fixture_file('csv_1.yml') }
9
+ end
10
+ ActiveExport.config.sources.should == { :default => fixture_file('csv_1.yml') }
11
+ end
12
+
13
+ describe '[](key)' do
14
+ context "configuration always_reload is false" do
15
+ before {
16
+ ActiveExport.configure do |config|
17
+ config.sources = { default: fixture_file('csv_1.yml') }
18
+ config.always_reload = false
19
+ end
20
+ ActiveExport[:default]
21
+ ActiveExport.should_not_receive(:load!).with(:default)
22
+ }
23
+ subject { ActiveExport[:default] }
24
+ it { should be_kind_of Hash }
25
+ it { subject['book_1'].should be_present }
26
+ it { subject[:book_2].should be_present }
27
+ end
28
+
29
+ context "configuration always_reload is true" do
30
+ before {
31
+ ActiveExport.configure do |config|
32
+ config.sources = { default: fixture_file('csv_1.yml') }
33
+ config.always_reload = true
34
+ end
35
+ }
36
+ it 'should call load!' do
37
+ ActiveExport[:default]
38
+ ActiveExport.should_receive(:load!).with(:default)
39
+ ActiveExport[:default]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :book do
3
+ sequence(:name) {|n| "book_#{n}" }
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ book_1:
2
+ label_prefix: book
3
+ methods:
4
+ - name
5
+ - author.name
6
+ - price
7
+ book_2:
8
+ label_prefix: book
9
+ methods:
10
+ - name
11
+ - author.name
12
+ - price: '(price * 1.095).ceil.to_i'
@@ -0,0 +1,5 @@
1
+ # coding: utf-8
2
+
3
+ class Author < ActiveRecord::Base
4
+ has_many :books
5
+ end
@@ -0,0 +1,7 @@
1
+ # coding: utf-8
2
+
3
+ class Book < ActiveRecord::Base
4
+ belongs_to :author
5
+ has_many :book_categories
6
+ has_many :categories, through: :book_categories
7
+ end
@@ -0,0 +1,6 @@
1
+ # coding: utf-8
2
+
3
+ class BookCategory < ActiveRecord::Base
4
+ belongs_to :book
5
+ belongs_to :category
6
+ end
@@ -0,0 +1,6 @@
1
+ # coding: utf-8
2
+
3
+ class Category < ActiveRecord::Base
4
+ has_many :book_categories
5
+ has_many :books, through: :book_categories
6
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+
3
+ require 'rails'
4
+ require 'active_record'
5
+ require 'action_controller/railtie'
6
+
7
+ module ActiveExport
8
+ class Application < Rails::Application
9
+ config.generators do |g|
10
+ g.orm :active_record
11
+ g.test_framework :rspec, fixture: false
12
+ end
13
+ config.active_support.deprecation = :notify
14
+ end
15
+ end
16
+ ActiveExport::Application.initialize!
17
+
18
+ ActiveRecord::Migration.verbose = false
19
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
20
+
21
+ support_path = File.expand_path(File.dirname(__FILE__))
22
+ require support_path + '/schema'
23
+
24
+ Dir["#{support_path}/model/**/*.rb"].each {|f| require f }
@@ -0,0 +1,20 @@
1
+ ActiveRecord::Schema.define(version: 1) do
2
+ create_table :books, force: true do |t|
3
+ t.string :name
4
+ t.integer :author_id
5
+ t.integer :price
6
+ end
7
+
8
+ create_table :authors, force: true do |t|
9
+ t.string :name
10
+ end
11
+
12
+ create_table :categories, force: true do |t|
13
+ t.string :name
14
+ end
15
+
16
+ create_table :book_categories, force: true do |t|
17
+ t.integer :book_id
18
+ t.integer :category_id
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ require 'tapp'
2
+ require 'rails/rails_support'
3
+ require 'rspec'
4
+ require 'rspec/rails'
5
+
6
+ require 'factory_girl'
7
+ FactoryGirl.find_definitions
8
+
9
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/active_export')
10
+
11
+ require 'database_cleaner'
12
+ DatabaseCleaner.clean_with :truncation
13
+ DatabaseCleaner.strategy = :transaction
14
+
15
+ RSpec.configure do |config|
16
+ config.mock_with :rspec
17
+ config.use_transactional_fixtures = false
18
+ config.treat_symbols_as_metadata_keys_with_true_values = true
19
+ config.filter_run focus: true
20
+ config.run_all_when_everything_filtered = true
21
+
22
+ config.before(:each) do
23
+ DatabaseCleaner.start
24
+ end
25
+
26
+ config.after(:each) do
27
+ DatabaseCleaner.clean
28
+ end
29
+ end
30
+
31
+ def fixture_file(filename)
32
+ File.expand_path(File.dirname(__FILE__)) + '/fixtures/' + filename
33
+ end
data/tasks/yard.rake ADDED
@@ -0,0 +1,6 @@
1
+ require 'yard'
2
+ require 'yard/rake/yardoc_task'
3
+
4
+ YARD::Rake::YardocTask.new do |t|
5
+ t.files = ['lib/**/*.rb']
6
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_export
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - kengos
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ description: Export to CSV from ActiveRecord collections.
31
+ email:
32
+ - kengo@kengos.jp
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - .yardopts
39
+ - Gemfile
40
+ - Guardfile
41
+ - LICENSE
42
+ - README.md
43
+ - Rakefile
44
+ - active_export.gemspec
45
+ - lib/active_export.rb
46
+ - lib/active_export/base.rb
47
+ - lib/active_export/configuration.rb
48
+ - lib/active_export/csv.rb
49
+ - lib/active_export/version.rb
50
+ - spec/active_export/base_spec.rb
51
+ - spec/active_export/csv_spec.rb
52
+ - spec/active_export/rails_support_spec.rb
53
+ - spec/active_export_spec.rb
54
+ - spec/factories/book.rb
55
+ - spec/fixtures/csv_1.yml
56
+ - spec/rails/model/author.rb
57
+ - spec/rails/model/book.rb
58
+ - spec/rails/model/book_category.rb
59
+ - spec/rails/model/category.rb
60
+ - spec/rails/rails_support.rb
61
+ - spec/rails/schema.rb
62
+ - spec/spec_helper.rb
63
+ - tasks/yard.rake
64
+ homepage: https://github.com/kengos/active_export
65
+ licenses: []
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 1.8.24
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Export to CSV from ActiveRecord collections.
88
+ test_files:
89
+ - spec/active_export/base_spec.rb
90
+ - spec/active_export/csv_spec.rb
91
+ - spec/active_export/rails_support_spec.rb
92
+ - spec/active_export_spec.rb
93
+ - spec/factories/book.rb
94
+ - spec/fixtures/csv_1.yml
95
+ - spec/rails/model/author.rb
96
+ - spec/rails/model/book.rb
97
+ - spec/rails/model/book_category.rb
98
+ - spec/rails/model/category.rb
99
+ - spec/rails/rails_support.rb
100
+ - spec/rails/schema.rb
101
+ - spec/spec_helper.rb
102
+ has_rdoc: