Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ Layout/SpaceAroundMethodCallOperator:
# AllowedMethods: enums
Lint/ConstantDefinitionInBlock:
Exclude:
- 'spec/comma/comma_spec.rb'
- 'spec/comma/rails/active_record_spec.rb'
- 'spec/comma/rails/data_mapper_collection_spec.rb'
- 'spec/comma/rails/mongoid_spec.rb'
Expand Down
89 changes: 49 additions & 40 deletions spec/comma/comma_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,86 +40,97 @@
end

it 'should extend Array to add a #to_comma method which will return CSV content for objects within the array' do
expected = "Title,Description,Issuer,ISBN-10,ISBN-13\nSmalltalk-80,Language and Implementation,ISBN,123123123,321321321\n" # rubocop:disable Layout/LineLength
expect(@books.to_comma).to eq(expected)
expect_csv(@books.to_comma,
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']])
end

it 'should return an empty string when generating CSV from an empty array' do
expect([].to_comma).to eq('')
end

it 'should change the style when specified' do
expect(@books.to_comma(:brief)).to eq("Name,Description\nSmalltalk-80,Language and Implementation\n")
expect_csv(@books.to_comma(:brief),
headers: %w[Name Description],
rows: [['Smalltalk-80', 'Language and Implementation']])
end

describe 'with :filename specified' do
after { File.delete('comma.csv') }

it 'should write to the file' do
@books.to_comma(filename: 'comma.csv')
expected = "Title,Description,Issuer,ISBN-10,ISBN-13\nSmalltalk-80,Language and Implementation,ISBN,123123123,321321321\n" # rubocop:disable Layout/LineLength
expect(File.read('comma.csv')).to eq(expected)
expect_csv(File.read('comma.csv'),
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']])
end

it 'should accept FasterCSV options' do
@books.to_comma(filename: 'comma.csv', col_sep: ';', force_quotes: true)
expected = "\"Title\";\"Description\";\"Issuer\";\"ISBN-10\";\"ISBN-13\"\n\"Smalltalk-80\";\"Language and Implementation\";\"ISBN\";\"123123123\";\"321321321\"\n" # rubocop:disable Layout/LineLength
expect(File.read('comma.csv')).to eq(expected)
expect_csv(File.read('comma.csv'),
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']],
col_sep: ';', force_quotes: true)
end
end

describe 'with FasterCSV options' do
it 'should not change when options are empty' do
expected = "Title,Description,Issuer,ISBN-10,ISBN-13\nSmalltalk-80,Language and Implementation,ISBN,123123123,321321321\n" # rubocop:disable Layout/LineLength
expect(@books.to_comma({})).to eq(expected)
expect_csv(@books.to_comma({}),
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']])
end

it 'should accept the options in #to_comma and generate the appropriate CSV' do
expected = "\"Title\";\"Description\";\"Issuer\";\"ISBN-10\";\"ISBN-13\"\n\"Smalltalk-80\";\"Language and Implementation\";\"ISBN\";\"123123123\";\"321321321\"\n" # rubocop:disable Layout/LineLength
expect(@books.to_comma(col_sep: ';', force_quotes: true)).to eq(expected)
expect_csv(@books.to_comma(col_sep: ';', force_quotes: true),
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']],
col_sep: ';', force_quotes: true)
end

it 'should change the style when specified' do
expect(@books.to_comma(style: :brief, col_sep: ';', force_quotes: true))
.to eq("\"Name\";\"Description\"\n\"Smalltalk-80\";\"Language and Implementation\"\n")
expect_csv(@books.to_comma(style: :brief, col_sep: ';', force_quotes: true),
headers: %w[Name Description],
rows: [['Smalltalk-80', 'Language and Implementation']],
col_sep: ';', force_quotes: true)
end
end
end

describe Comma, 'defining CSV descriptions' do
describe 'with an unnamed description' do
before do
class Foo
@foo_class = define_comma_class do
comma do; end
end
end

it 'should name the current description :default if no name has been provided' do
expect(Foo.comma_formats).not_to be_empty
expect(Foo.comma_formats[:default]).not_to be_nil
expect(@foo_class.comma_formats).not_to be_empty
expect(@foo_class.comma_formats[:default]).not_to be_nil
end
end

describe 'with a named description' do
before do
class Bar
@bar_class = define_comma_class do
comma do; end
comma :detailed do; end
end
end

it 'should use the provided name to index the comma format' do
expect(Bar.comma_formats).not_to be_empty
expect(Bar.comma_formats[:default]).not_to be_nil
expect(Bar.comma_formats[:detailed]).not_to be_nil
expect(@bar_class.comma_formats).not_to be_empty
expect(@bar_class.comma_formats[:default]).not_to be_nil
expect(@bar_class.comma_formats[:detailed]).not_to be_nil
end
end
end

describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable Metrics/BlockLength
describe 'with unnamed descriptions' do
before do
class Foo
foo_class = define_comma_class do
attr_accessor :content
comma do; content; end

Expand All @@ -128,7 +139,7 @@ def initialize(content)
end
end

@foo = Foo.new('content')
@foo = foo_class.new('content')
end

it 'should return and array of data content, using the :default CSV description if none requested' do
Expand All @@ -146,7 +157,7 @@ def initialize(content)

describe 'with named descriptions' do
before do
class Foo
foo_class = define_comma_class do
attr_accessor :content
comma :detailed do; content; end

Expand All @@ -155,7 +166,7 @@ def initialize(content)
end
end

@foo = Foo.new('content')
@foo = foo_class.new('content')
end

it 'should return and array of data content, using the :default CSV description if none requested' do
Expand All @@ -179,7 +190,7 @@ def initialize(content)

describe 'with block' do # rubocop:disable Metrics/BlockLength
before do
class Foo
foo_class = define_comma_class do
attr_accessor :content, :created_at, :updated_at
comma do
content
Expand All @@ -199,7 +210,7 @@ def initialize(content, created_at = Time.now, updated_at = Time.now)

@time = Time.now
@content = 'content ' * 5
@foo = Foo.new @content, @time, @time
@foo = foo_class.new @content, @time, @time
end

it 'should return yielded values by block' do
Expand Down Expand Up @@ -265,7 +276,7 @@ def initialize(content, created_at = Time.now, updated_at = Time.now)

describe 'on objects using Single Table Inheritance' do # rubocop:disable Metrics/BlockLength
before do
class MySuperClass
super_class = define_comma_class do
attr_accessor :content
comma do; content end

Expand All @@ -274,19 +285,18 @@ def initialize(content)
end
end

class ChildClassComma < MySuperClass
child_class_comma = define_comma_class(super_class) do
comma do; content end

def initialize(content)
@content = 'sub-' + content
end
end

class ChildClassNoComma < MySuperClass
end
child_class_no_comma = define_comma_class(super_class) {}

@childComma = ChildClassComma.new('content')
@childNoComma = ChildClassNoComma.new('content')
@childComma = child_class_comma.new('content')
@childNoComma = child_class_no_comma.new('content')
end

it 'should return and array of data content, as defined in comma block in child class' do
Expand All @@ -298,7 +308,7 @@ class ChildClassNoComma < MySuperClass
end

it 'should reflect changes to the superclass format made after the subclass was defined' do
class ReopenedSuperClass
reopened_super_class = define_comma_class do
attr_accessor :content
comma do; content end

Expand All @@ -307,24 +317,23 @@ def initialize(content)
end
end

class ReopenedChildNoComma < ReopenedSuperClass
end
reopened_child_no_comma = define_comma_class(reopened_super_class) {}

ReopenedSuperClass.class_eval do
reopened_super_class.class_eval do
comma do
content(&:upcase)
end
end

child = ReopenedChildNoComma.new('content')
child = reopened_child_no_comma.new('content')
expect(child.to_comma).to eq(%w[SUPER-CONTENT])
end
end
end

describe Comma, '__use__ keyword' do
before(:all) do
@obj = Class.new(Struct.new(:id, :title, :description)) do
@obj = define_comma_class(Struct.new(:id, :title, :description)) do
comma do
title
__use__ :description
Expand All @@ -348,7 +357,7 @@ class ReopenedChildNoComma < ReopenedSuperClass

describe Comma, '__use__ keyword with a circular reference' do
it 'should raise Comma::CircularStyleReference instead of overflowing the stack' do
obj = Class.new(Struct.new(:id, :title)) do
obj = define_comma_class(Struct.new(:id, :title)) do
comma :a do
title
__use__ :b
Expand All @@ -363,7 +372,7 @@ class ReopenedChildNoComma < ReopenedSuperClass
end

it 'should raise Comma::CircularStyleReference for direct self-reference' do
obj = Class.new(Struct.new(:id)) do
obj = define_comma_class(Struct.new(:id)) do
comma :a do
__use__ :a
end
Expand Down
6 changes: 3 additions & 3 deletions spec/comma/data_extractor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

describe Comma::DataExtractor, 'id attribute' do
before do
@data = Class.new(Struct.new(:id)) do
@data = define_comma_class(Struct.new(:id)) do
comma do
id 'ID' do |_id| '42' end
end
Expand All @@ -59,7 +59,7 @@

describe Comma::DataExtractor, 'with static column method' do
before do
@data = Class.new(Struct.new(:id, :name)) do
@data = define_comma_class(Struct.new(:id, :name)) do
comma do
__static_column__
__static_column__ 'STATIC'
Expand All @@ -76,7 +76,7 @@

describe Comma::DataExtractor, 'nil value' do
before do
@data = Class.new(Struct.new(:id, :name)) do
@data = define_comma_class(Struct.new(:id, :name)) do
comma do
name
name 'Name'
Expand Down
2 changes: 1 addition & 1 deletion spec/comma/header_extractor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

describe Comma::HeaderExtractor, 'with static column method' do
before do
@headers = Class.new(Struct.new(:id, :name)) do
@headers = define_comma_class(Struct.new(:id, :name)) do
comma do
__static_column__
__static_column__ 'STATIC'
Expand Down
41 changes: 13 additions & 28 deletions spec/controllers/users_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,9 @@
expect(response.media_type).to eq 'text/csv'
expect(response.header['Content-Disposition']).to include('filename="data.csv"')

expected_content = <<-CSV.gsub(/^\s+/, '')
First name,Last name,Name
Fred,Flintstone,Fred Flintstone
Wilma,Flintstone,Wilma Flintstone
CSV

expect(response.body).to eq expected_content
expect_csv(response.body,
headers: ['First name', 'Last name', 'Name'],
rows: [['Fred', 'Flintstone', 'Fred Flintstone'], ['Wilma', 'Flintstone', 'Wilma Flintstone']])
end

describe 'with comma options' do
Expand All @@ -53,13 +49,9 @@

get :with_custom_style, format: :csv

expected_content = <<-CSV.gsub(/^\s+/, '')
First name,Last name
Fred,Flintstone
Wilma,Flintstone
CSV

expect(response.body).to eq expected_content
expect_csv(response.body,
headers: ['First name', 'Last name'],
rows: [%w[Fred Flintstone], %w[Wilma Flintstone]])
end
end

Expand Down Expand Up @@ -131,13 +123,9 @@ def get_(name, **args)
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/csv'

expected_content = <<-CSV.gsub(/^\s+/, '')
First name,Last name,Name
Fred,Flintstone,Fred Flintstone
Wilma,Flintstone,Wilma Flintstone
CSV

expect(response.body).to eq expected_content
expect_csv(response.body,
headers: ['First name', 'Last name', 'Name'],
rows: [['Fred', 'Flintstone', 'Fred Flintstone'], ['Wilma', 'Flintstone', 'Wilma Flintstone']])
end

it 'should allow toggling off' do
Expand All @@ -161,13 +149,10 @@ def get_(name, **args)
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/csv'

expected_content = <<-CSV.gsub(/^\s+/, '')
"First name","Last name","Name"
"Fred","Flintstone","Fred Flintstone"
"Wilma","Flintstone","Wilma Flintstone"
CSV

expect(response.body).to eq expected_content
expect_csv(response.body,
headers: ['First name', 'Last name', 'Name'],
rows: [['Fred', 'Flintstone', 'Fred Flintstone'], ['Wilma', 'Flintstone', 'Wilma Flintstone']],
force_quotes: true)
end

it 'should allow combinations of options' do
Expand Down
12 changes: 12 additions & 0 deletions spec/support/comma_class_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

# Defines an anonymous class for use in a single example, avoiding
# constants leaking into the global namespace across the spec suite.
# Pass `base` to build on a superclass (e.g. a Struct).
#
# book_class = define_comma_class(Struct.new(:title)) do
# comma { title }
# end
def define_comma_class(base = Object, &block)
Class.new(base, &block)
end
14 changes: 14 additions & 0 deletions spec/support/csv_expectation_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

# Builds the expected CSV string from headers/rows so specs don't hand-roll
# comma-joined strings, then asserts it against the actual output.
# `csv_options` are forwarded to CSV.generate (e.g. col_sep:, force_quotes:).
#
# expect_csv(books.to_comma, headers: %w[Title Author], rows: [['Smalltalk-80', 'Kay']])
def expect_csv(output, headers:, rows:, **csv_options)
expected = CSV.generate(**csv_options) do |csv|
csv << headers
rows.each { |row| csv << row }
end
expect(output).to eq(expected)
end
Loading