cloudxls-rails 0.4.3 → 0.5.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.
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = CloudXLSRails::VERSION
17
17
 
18
- gem.add_dependency('cloudxls', '~> 0.4.0')
18
+ gem.add_dependency('cloudxls', '~> 0.5.0')
19
19
 
20
20
  gem.add_development_dependency "rake"
21
21
  gem.add_development_dependency "webmock"
@@ -0,0 +1,88 @@
1
+ require 'active_model/serialization'
2
+
3
+ module ActiveModel
4
+ module Serializers
5
+ module CSV
6
+ include ActiveModel::Serialization
7
+
8
+ # Returns an array representing the model. Some configuration can be
9
+ # passed through +options+.
10
+ #
11
+ # Without any +options+, the returned Array will include all the model's
12
+ # attributes.
13
+ #
14
+ # user = User.find(1)
15
+ # user.as_csv
16
+ # # => [1, "Konata Izumi", 16, "2006-08-01", true]
17
+ #
18
+ # The :only and :except options can be used to limit
19
+ # the attributes included, and work similar to the +attributes+ method.
20
+ #
21
+ # user.as_csv(only: [:id, :name])
22
+ # # => [1, "Konata Izumi"]
23
+ #
24
+ # user.as_csv(except: [:id, :created_at, :age])
25
+ # # => ["Konata Izumi", true]
26
+ #
27
+ # To include the result of some method calls on the model use :methods:
28
+ #
29
+ # user.as_csv(methods: :permalink)
30
+ # # => [1, "Konata Izumi", 16, "2006-08-01", true, "1-konata-izumi"]
31
+ #
32
+ def as_csv(options = nil)
33
+ options ||= {}
34
+
35
+ attribute_names = attributes.keys
36
+ if only = options[:only]
37
+ attribute_names = Array(only).map(&:to_s).select do |key|
38
+ attribute_names.include?(key)
39
+ end
40
+ elsif except = options[:except]
41
+ attribute_names -= Array(except).map(&:to_s)
42
+ end
43
+
44
+ arr = []
45
+ attribute_names.each do |n|
46
+ arr.push(read_attribute_for_serialization(n).as_csv)
47
+ end
48
+
49
+ Array(options[:methods]).each do |m|
50
+ if respond_to?(m)
51
+ val = send(m)
52
+ if idx = attribute_names.index(m.to_s)
53
+ arr[idx] = val
54
+ else
55
+ arr.push(val)
56
+ end
57
+ end
58
+ end
59
+
60
+ arr
61
+ end
62
+
63
+ private
64
+
65
+ # Hook method defining how an attribute value should be retrieved for
66
+ # serialization. By default this is assumed to be an instance named after
67
+ # the attribute. Override this method in subclasses should you need to
68
+ # retrieve the value for a given attribute differently:
69
+ #
70
+ # class MyClass
71
+ # include ActiveModel::Validations
72
+ #
73
+ # def initialize(data = {})
74
+ # @data = data
75
+ # end
76
+ #
77
+ # def read_attribute_for_serialization(key)
78
+ # @data[key]
79
+ # end
80
+ # end
81
+ alias :read_attribute_for_serialization :send
82
+
83
+ end
84
+ end
85
+ end
86
+
87
+ ActiveRecord::Base.send(:include, ActiveModel::Serializers::CSV)
88
+
@@ -0,0 +1,9 @@
1
+ require 'active_support/time_with_zone'
2
+
3
+ module ActiveSupport
4
+ class TimeWithZone
5
+ def as_csv(options = nil)
6
+ to_datetime.as_csv
7
+ end
8
+ end
9
+ end
@@ -33,12 +33,11 @@ end
33
33
 
34
34
  ActionController::Renderers.add :csv do |scope, options|
35
35
  filename = options.fetch(:filename, "data-#{DateTime.now.to_s}.csv")
36
- columns = options[:columns]
37
36
 
38
37
  if options[:stream]
39
38
  CloudXLSRails::CSVResponder.stream!(self, scope, options)
40
39
  else # no stream:
41
- data = CloudXLS::CSVWriter.text(scope, {:columns => columns})
40
+ data = CloudXLS::CSVWriter.text(scope, options)
42
41
 
43
42
  send_data data,
44
43
  type: Mime::CSV,
@@ -6,13 +6,12 @@ end
6
6
  module CloudXLSRails
7
7
  class XLSResponder
8
8
  def self.redirect!(controller, scope, options)
9
- columns = options.fetch(:columns, nil)
10
9
  xdata = options[:data] || {}
11
10
  unless (xdata.has_key?(:text) ||
12
11
  xdata.has_key?(:url ) ||
13
12
  xdata.has_key?(:file) )
14
13
 
15
- xdata[:text] = CloudXLS::CSVWriter.text(scope, {:columns => columns})
14
+ xdata[:text] = CloudXLS::CSVWriter.text(scope, options)
16
15
  end
17
16
 
18
17
  xopts = {:data => xdata}
@@ -6,13 +6,12 @@ end
6
6
  module CloudXLSRails
7
7
  class XLSXResponder
8
8
  def self.redirect!(controller, scope, options)
9
- columns = options.fetch(:columns, nil)
10
9
  xdata = options[:data] || {}
11
10
  unless (xdata.has_key?(:text) ||
12
11
  xdata.has_key?(:url ) ||
13
12
  xdata.has_key?(:file) )
14
13
 
15
- xdata[:text] = CloudXLS::CSVWriter.text(scope, {:columns => columns})
14
+ xdata[:text] = CloudXLS::CSVWriter.text(scope, options)
16
15
  end
17
16
 
18
17
  xopts = {:data => xdata}
@@ -1,3 +1,3 @@
1
1
  module CloudXLSRails
2
- VERSION = '0.4.3'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -2,6 +2,8 @@ require 'cloudxls' # cloudxls gem
2
2
 
3
3
  require 'action_controller'
4
4
  require 'cloudxls-rails/version'
5
+ require 'cloudxls-rails/activesupport'
6
+ require 'cloudxls-rails/activemodel'
5
7
  require 'cloudxls-rails/handlers/csv'
6
8
  require 'cloudxls-rails/handlers/xls'
7
9
  require 'cloudxls-rails/handlers/xlsx'
@@ -1,12 +1,58 @@
1
1
  require 'spec_helper'
2
2
 
3
+ describe CloudXLS::Util do
4
+ describe "titles_for_serialize_options" do
5
+ it "should work with a Post.all" do
6
+ expect( CloudXLS::Util.titles_for_serialize_options(Post.new, :only => "title") ).to eq(["title"])
7
+ end
8
+ end
9
+ end
10
+
3
11
  describe "CloudXLS::CSVWriter" do
4
12
  before do
5
13
  @writer = CloudXLS::CSVWriter
6
14
  end
7
15
 
8
16
  describe "with array" do
9
- # spec'ed in cloudlxs-ruby gem
17
+ it "should not titleize" do
18
+ expect( @writer.text([['foo','bar'],[1,2]]) ).to eq("foo,bar\n1,2")
19
+ end
20
+
21
+ it "should escape titles" do
22
+ expect( @writer.text([['bar"baz']]) ).to eq("\"bar\"\"baz\"")
23
+ end
24
+
25
+ it "should escape rows" do
26
+ expect( @writer.text([['title'],['bar"baz']]) ).to eq("title\n\"bar\"\"baz\"")
27
+ end
28
+
29
+ it "should write YYYY-MM-DD for Date" do
30
+ expect( @writer.text([[Date.new(2012,12,24)]]) ).to eq("2012-12-24")
31
+ end
32
+
33
+ it "should write xmlschema for DateTime" do
34
+ # TODO: make UTC consistent
35
+ expect( DateTime.new(2012,12,24,18,30,5,'+0000').as_csv ).to eq("2012-12-24T18:30:05.000+0000")
36
+ expect( [DateTime.new(2012,12,24,18,30,5,'+0000')].as_csv ).to eq(["2012-12-24T18:30:05.000+0000"])
37
+ expect( @writer.text([[DateTime.new(2012,12,24,18,30,5,'+0000')]]) ).to eq("2012-12-24T18:30:05.000+0000")
38
+ expect( @writer.text([[DateTime.new(2012,12,24,18,30,5,'+0000').to_time.utc]]) ).to eq("2012-12-24T18:30:05.000+0000")
39
+ end
40
+
41
+ it "should write nothing for nil" do
42
+ expect( @writer.text([[nil,nil]]) ).to eq(",")
43
+ end
44
+
45
+ it "should write \"\" for empty string" do
46
+ expect( @writer.text([["",""]]) ).to eq('"",""')
47
+ end
48
+
49
+ it "should write integers" do
50
+ expect( @writer.text([[-1,0,1,1_000_000]]) ).to eq('-1,0,1,1000000')
51
+ end
52
+
53
+ it "should write floats" do
54
+ expect( @writer.text([[-1.0,0.0,1.0,1_000_000.0,1.234567]]) ).to eq('-1.0,0.0,1.0,1000000.0,1.234567')
55
+ end
10
56
  end
11
57
 
12
58
  describe "#text with AR" do
@@ -22,29 +68,29 @@ describe "CloudXLS::CSVWriter" do
22
68
  :published => false)
23
69
  end
24
70
 
25
- it "given no records should just return titles" do
71
+ it "given no records returns empty string" do
26
72
  Post.delete_all
27
- expect( @writer.text(Post.all, :columns => [:title, :visits]) ).to eq("Title,Visits")
73
+ expect( @writer.text(Post.all, :only => [:title, :visits]) ).to eq("")
28
74
  end
29
75
 
30
76
  it "should work with a Post.all" do
31
- expect( @writer.text(Post.all, :columns => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
77
+ expect( @writer.text(Post.all, :only => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
32
78
  end
33
79
 
34
80
  it "should work with a Post.limit" do
35
- expect( @writer.text(Post.limit(10), :columns => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
81
+ expect( @writer.text(Post.limit(10), :only => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
36
82
  end
37
83
 
38
84
  it "should work with a Post.all.to_a" do
39
- expect( @writer.text(Post.all.to_a, :columns => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
85
+ expect( @writer.text(Post.all.to_a, :only => [:title, :visits]) ).to eq("Title,Visits\nhello world,12032")
40
86
  end
41
87
 
42
88
  it "should write xmlschema for DateTime" do
43
- expect( @writer.text(Post.all, :columns => [:expired_at]) ).to eq("Expired At\n2013-12-25T12:30:30.000+0000")
89
+ expect( @writer.text(Post.all, :only => [:expired_at]) ).to eq("Expired At\n2013-12-25T12:30:30.000+0000")
44
90
  end
45
91
 
46
92
  it "should write YYYY-MM-DD for Date" do
47
- expect( @writer.text(Post.all, :columns => [:published_on]) ).to eq("Published On\n2013-12-24")
93
+ expect( @writer.text(Post.all, :only => [:published_on]) ).to eq("Published On\n2013-12-24")
48
94
  end
49
95
  end
50
96
  end
@@ -14,6 +14,13 @@ describe 'Request', :type => :request do
14
14
  :published => false)
15
15
  end
16
16
 
17
+ it "#as_csv" do
18
+ expect( @post.as_csv(except: [:unix_timestamp, :created_at, :updated_at]) ).to eq([@post.id, "hello world", 12_032, 0.24, "2013-12-24", "2013-12-25T12:30:30.000+0000", false])
19
+ expect( @post.as_csv(only: [:title]) ).to eq(["hello world"])
20
+ expect( @post.as_csv(only: [:title, :visits]) ).to eq(["hello world", 12_032])
21
+ expect( @post.as_csv(only: [:expired_at]) ).to eq(["2013-12-25T12:30:30.000+0000"])
22
+ end
23
+
17
24
  it "has a working test_app" do
18
25
  visit '/'
19
26
  page.should have_content "Users"
@@ -27,6 +34,14 @@ describe 'Request', :type => :request do
27
34
  ].join("\n")
28
35
  end
29
36
 
37
+ it "/posts/all_columns.csv streams csv" do
38
+ visit '/posts/all_columns.csv'
39
+ page.should have_content [
40
+ "Id,Title,Visits,Conversion Rate,Published On,Expired At,Published,Unix Timestamp,Created At,Updated At",
41
+ "1,hello world,12032,0.24,2013-12-24,2013-12-25T12:30:30.000+0000,false,2013-12-25T12:30:30.000+0000,#{@post.created_at.as_csv},#{@post.updated_at.as_csv}"
42
+ ].join("\n")
43
+ end
44
+
30
45
  it "/posts/stream.csv streams csv" do
31
46
  visit '/posts/stream.csv'
32
47
  page.should have_content [
@@ -3,19 +3,23 @@ class PostsController < ApplicationController
3
3
 
4
4
  def index
5
5
  respond_with(Post.all,
6
- :columns => export_attributes)
6
+ :only => export_attributes)
7
+ end
8
+
9
+ def all_columns
10
+ respond_with(Post.all.to_a)
7
11
  end
8
12
 
9
13
  def stream
10
14
  respond_with(Post.all,
11
15
  :stream => true,
12
- :columns => export_attributes)
16
+ :only => export_attributes)
13
17
  end
14
18
 
15
19
  def stream_with_custom_url
16
20
  respond_with(Post.all,
17
21
  :stream => "/successful_redirect",
18
- :columns => export_attributes)
22
+ :only => export_attributes)
19
23
  end
20
24
 
21
25
  # Used for stub/mocking a redirect request
@@ -3,6 +3,7 @@ TestApp::Application.routes.draw do
3
3
  collection do
4
4
  get "stream"
5
5
  get "stream_with_custom_url"
6
+ get "all_columns"
6
7
  end
7
8
  end
8
9
  get "successful_redirect" => "posts#successful_redirect"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudxls-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.4.0
21
+ version: 0.5.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 0.4.0
29
+ version: 0.5.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: rake
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -120,6 +120,8 @@ files:
120
120
  - Rakefile
121
121
  - cloudxls-rails.gemspec
122
122
  - lib/cloudxls-rails.rb
123
+ - lib/cloudxls-rails/activemodel.rb
124
+ - lib/cloudxls-rails/activesupport.rb
123
125
  - lib/cloudxls-rails/handlers/csv.rb
124
126
  - lib/cloudxls-rails/handlers/xls.rb
125
127
  - lib/cloudxls-rails/handlers/xlsx.rb