Repository: comma-csv/comma
Branch: master
Commit: 0f639466331e
Files: 48
Total size: 55.7 KB
Directory structure:
gitextract_uknkcqm5/
├── .coveralls.yml
├── .github/
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── .rubocop_todo.yml
├── .travis.yml
├── Appraisals
├── Gemfile
├── MIT-LICENSE
├── README.md
├── Rakefile
├── comma.gemspec
├── gemfiles/
│ ├── active6.0.6.gemfile
│ ├── active6.1.7.6.gemfile
│ ├── active7.0.8.gemfile
│ ├── active7.1.3.gemfile
│ ├── rails6.0.6.gemfile
│ ├── rails6.1.7.6.gemfile
│ ├── rails7.0.8.gemfile
│ └── rails7.1.3.gemfile
├── init.rb
├── lib/
│ ├── comma/
│ │ ├── array.rb
│ │ ├── data_extractor.rb
│ │ ├── data_mapper_collection.rb
│ │ ├── extractor.rb
│ │ ├── generator.rb
│ │ ├── header_extractor.rb
│ │ ├── mongoid.rb
│ │ ├── object.rb
│ │ ├── relation.rb
│ │ └── version.rb
│ └── comma.rb
└── spec/
├── comma/
│ ├── comma_spec.rb
│ ├── data_extractor_spec.rb
│ ├── header_extractor_spec.rb
│ └── rails/
│ ├── active_record_spec.rb
│ ├── data_mapper_collection_spec.rb
│ └── mongoid_spec.rb
├── controllers/
│ └── users_controller_spec.rb
├── non_rails_app/
│ └── ruby_classes.rb
├── rails_app/
│ ├── active_record/
│ │ ├── config.rb
│ │ └── models.rb
│ ├── data_mapper/
│ │ └── config.rb
│ ├── mongoid/
│ │ └── config.rb
│ ├── rails_app.rb
│ └── tmp/
│ └── .gitkeep
└── spec_helper.rb
================================================
FILE CONTENTS
================================================
================================================
FILE: .coveralls.yml
================================================
service_name: travis-ci
================================================
FILE: .github/workflows/build.yml
================================================
name: Build
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
ruby: ['3.0', '3.1', '3.2', '3.3']
gemfile: ['active6.0.6', 'active6.1.7.6', 'active7.0.8', 'active7.1.3', 'rails6.0.6', 'rails6.1.7.6', 'rails7.0.8', 'rails7.1.3']
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
RUBY_OPT: --disable=did_you_mean
services:
mongodb:
image: mongo:4.4.10
ports:
- 8081:8081
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
cache-version: 1
- run: bundle install --jobs 2 --retry 3
- run: bundle exec rubocop -P
- run: bundle exec rspec -f d spec
================================================
FILE: .gitignore
================================================
pkg/*
.*.swp
*~
.bundle
spec/rails_app/log
spec/rails_app/db/development.sqlite*
.rbx/
.ruby-*
coverage/*
================================================
FILE: .rspec
================================================
--colour
================================================
FILE: .rubocop.yml
================================================
inherit_from: .rubocop_todo.yml
require: rubocop-performance
AllCops:
DisplayCopNames: true
Exclude:
- 'gemfiles/**/*'
- 'vendor/**/*'
NewCops: enable
TargetRubyVersion: 2.5
Layout/LineLength:
IgnoreCopDirectives: true
Max: 120
Naming/FileName:
Exclude:
- 'Appraisals'
Naming/VariableNumber:
EnforcedStyle: snake_case
================================================
FILE: .rubocop_todo.yml
================================================
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2024-01-20 09:02:51 UTC using RuboCop version 1.30.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Include.
# Include: **/*.gemspec
Gemspec/DeprecatedAttributeAssignment:
Exclude:
- 'comma.gemspec'
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Include.
# Include: **/*.gemspec
Gemspec/RequireMFA:
Exclude:
- 'comma.gemspec'
# Offense count: 1
# Configuration parameters: Include.
# Include: **/*.gemspec
Gemspec/RequiredRubyVersion:
Exclude:
- 'comma.gemspec'
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, AllowAdjacentOneLineDefs, NumberOfEmptyLines.
Layout/EmptyLineBetweenDefs:
Exclude:
- 'spec/rails_app/rails_app.rb'
# Offense count: 4
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowAliasSyntax, AllowedMethods.
# AllowedMethods: alias_method, public, protected, private
Layout/EmptyLinesAroundAttributeAccessor:
Exclude:
- 'spec/comma/comma_spec.rb'
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
Layout/SpaceAroundMethodCallOperator:
Exclude:
- 'spec/controllers/users_controller_spec.rb'
# Offense count: 17
# Configuration parameters: AllowedMethods.
# 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'
# Offense count: 4
# Configuration parameters: AllowComments, AllowEmptyLambdas.
Lint/EmptyBlock:
Exclude:
- 'spec/comma/comma_spec.rb'
- 'spec/comma/rails/data_mapper_collection_spec.rb'
# Offense count: 1
Lint/MissingSuper:
Exclude:
- 'spec/comma/comma_spec.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
Lint/NonDeterministicRequireOrder:
Exclude:
- 'spec/spec_helper.rb'
# Offense count: 2
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 22
# Offense count: 3
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
Metrics/MethodLength:
Max: 16
# Offense count: 2
# Configuration parameters: EnforcedStyle, AllowedIdentifiers, AllowedPatterns.
# SupportedStyles: snake_case, camelCase
Naming/VariableName:
Exclude:
- 'spec/comma/comma_spec.rb'
# Offense count: 14
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, IgnoredMethods, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
# FunctionalMethods: let, let!, subject, watch
# IgnoredMethods: lambda, proc, it
Style/BlockDelimiters:
Exclude:
- 'spec/comma/comma_spec.rb'
- 'spec/comma/data_extractor_spec.rb'
- 'spec/comma/header_extractor_spec.rb'
# Offense count: 11
# Configuration parameters: AllowedConstants.
Style/Documentation:
Exclude:
- 'spec/**/*'
- 'test/**/*'
- 'lib/comma/array.rb'
- 'lib/comma/data_extractor.rb'
- 'lib/comma/data_mapper_collection.rb'
- 'lib/comma/extractor.rb'
- 'lib/comma/generator.rb'
- 'lib/comma/header_extractor.rb'
- 'lib/comma/mongoid.rb'
- 'lib/comma/object.rb'
- 'lib/comma/relation.rb'
# Offense count: 3
Style/MissingRespondToMissing:
Exclude:
- 'lib/comma/data_extractor.rb'
- 'lib/comma/header_extractor.rb'
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
Style/RedundantBegin:
Exclude:
- 'spec/spec_helper.rb'
# Offense count: 6
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Mode.
Style/StringConcatenation:
Exclude:
- 'spec/comma/comma_spec.rb'
- 'spec/comma/rails/active_record_spec.rb'
- 'spec/spec_helper.rb'
================================================
FILE: .travis.yml
================================================
sudo: false
services: mongodb
language: ruby
cache: bundler
rvm:
- 2.4.10
- 2.5.8
- 2.6.6
- 2.7.2
gemfile:
- gemfiles/active5.0.7.2.gemfile
- gemfiles/active5.1.7.gemfile
- gemfiles/active5.2.4.3.gemfile
- gemfiles/active6.0.3.1.gemfile
- gemfiles/active6.1.0.gemfile
- gemfiles/rails5.0.7.2.gemfile
- gemfiles/rails5.1.7.gemfile
- gemfiles/rails5.2.4.3.gemfile
- gemfiles/rails6.0.3.1.gemfile
- gemfiles/rails6.1.0.gemfile
- gemfiles/railsedge.gemfile
matrix:
exclude:
- rvm: 2.4.10
gemfile: gemfiles/active6.0.3.1.gemfile
- rvm: 2.4.10
gemfile: gemfiles/active6.1.0.gemfile
- rvm: 2.4.10
gemfile: gemfiles/rails6.0.3.1.gemfile
- rvm: 2.4.10
gemfile: gemfiles/rails6.1.0.gemfile
- rvm: 2.4.10
gemfile: gemfiles/railsedge.gemfile
- rvm: 2.5.8
gemfile: gemfiles/railsedge.gemfile
fast_finish: true
before_install:
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
- gem install bundler -v '< 2'
script:
- bundle exec rubocop -P
- bundle exec rspec -f d spec
================================================
FILE: Appraisals
================================================
# frozen_string_literal: true
appraise 'rails6.0.6' do
gem 'rails', '6.0.6'
gem 'rspec-rails'
gem 'test-unit'
end
appraise 'active6.0.6' do
gem 'activesupport', '6.0.6'
gem 'activerecord', '6.0.6'
end
appraise 'rails6.1.7.6' do
gem 'rails', '6.1.7.6'
gem 'rspec-rails'
gem 'test-unit'
end
appraise 'active6.1.7.6' do
gem 'activesupport', '6.1.7.6'
gem 'activerecord', '6.1.7.6'
end
appraise 'rails7.0.8' do
gem 'rails', '7.0.8'
gem 'rspec-rails'
end
appraise 'active7.0.8' do
gem 'activesupport', '7.0.8'
gem 'activerecord', '7.0.8'
end
appraise 'rails7.1.3' do
gem 'rails', '7.1.3'
gem 'rspec-rails'
end
appraise 'active7.1.3' do
gem 'activesupport', '7.1.3'
gem 'activerecord', '7.1.3'
end
================================================
FILE: Gemfile
================================================
# frozen_string_literal: true
source 'https://rubygems.org'
gemspec
gem 'coveralls', require: false
gem 'rubocop', '~> 1.30.0', require: false
gem 'rubocop-performance', require: false
gem 'sqlite3'
================================================
FILE: MIT-LICENSE
================================================
Copyright (c) 2009 Marcus Crafter
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# Comma
A library to generate comma seperated value (CSV) for Ruby objects like ActiveRecord and Array
[](http://badge.fury.io/rb/comma) [](https://github.com/comma-csv/comma/actions/workflows/build.yml) [](https://codeclimate.com/github/comma-csv/comma)
## Getting Started
### Prerequisites
You need to use ruby 3.0 or later. If you generate CSV from ActiveRecord models, you need to have ActiveRecord 6.0 or later.
### Installing
Comma is distributed as a gem, best installed via Bundler.
Include the gem in your Gemfile:
```ruby
gem 'comma', '~> 4.8.0'
```
Or, if you want to live life on the edge, you can get master from the main comma repository:
```ruby
gem 'comma', git: 'git://github.com/comma-csv/comma.git'
```
Then, run `bundle install`.
### Usage
See [this page](https://github.com/comma-csv/comma/wiki) for usages.
## Running the tests
To run the test suite across multiple gem file sets, we're using [Appraisal](https://github.com/thoughtbot/appraisal), use the following commands:
```sh
$ bundle exec appraisal install
$ bundle exec appraisal rake spec
```
## Contributing
## Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/comma-csv/comma/tags).
## Authors
* Marcus Crafter - Initial work
* Tom Meier - Initial work
* Eito Katagiri
## License
This project is licensed under the MIT License - see the [MIT-LICENSE](https://github.com/comma-csv/comma/blob/master/MIT-LICENSE) file fore details.
================================================
FILE: Rakefile
================================================
# frozen_string_literal: true
require 'bundler/setup'
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
spec.pattern = FileList['spec/**/*_spec.rb']
end
require 'rubocop/rake_task'
RuboCop::RakeTask.new
task default: :spec
================================================
FILE: comma.gemspec
================================================
# frozen_string_literal: true
$LOAD_PATH.push File.expand_path('lib', __dir__)
require 'comma/version'
Gem::Specification.new do |s|
s.name = 'comma'
s.version = Comma::VERSION
s.authors = ['Marcus Crafter', 'Tom Meier']
s.email = ['crafterm@redartisan.com', 'tom@venombytes.com']
s.homepage = 'http://github.com/comma-csv/comma'
s.summary = %(Ruby Comma Seperated Values generation library)
s.description = %(Ruby Comma Seperated Values generation library)
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.require_paths = ['lib']
s.licenses = ['MIT']
s.add_dependency 'activesupport', '>= 4.2.0'
s.add_development_dependency 'appraisal', ['~> 1.0.0']
s.add_development_dependency 'minitest', '5.14.4'
s.add_development_dependency 'rake', '~> 13.0.1'
s.add_development_dependency 'rspec', ['~> 3.5.0']
s.add_development_dependency 'rspec-activemodel-mocks'
s.add_development_dependency 'rspec-its'
end
================================================
FILE: gemfiles/active6.0.6.gemfile
================================================
# This file was generated by Appraisal
source "https://rubygems.org"
gem "coveralls", :require => false
gem "rubocop", "~> 1.30.0", :require => false
gem "rubocop-performance", :require => false
gem "sqlite3"
gem "activesupport", "6.0.6"
gem "activerecord", "6.0.6"
gemspec :path => "../"
================================================
FILE: gemfiles/active6.1.7.6.gemfile
================================================
# This file was generated by Appraisal
source "https://rubygems.org"
gem "coveralls", :require => false
gem "rubocop", "~> 1.30.0", :require => false
gem "rubocop-performance", :require => false
gem "sqlite3"
gem "activesupport", "6.1.7.6"
gem "activerecord", "6.1.7.6"
gemspec :path => "../"
================================================
FILE: gemfiles/active7.0.8.gemfile
================================================
# This file was generated by Appraisal
source "https://rubygems.org"
gem "coveralls", :require => false
gem "rubocop", "~> 1.30.0", :require => false
gem "rubocop-performance", :require => false
gem "sqlite3"
gem "activesupport", "7.0.8"
gem "activerecord", "7.0.8"
gemspec :path => "../"
================================================
FILE: gemfiles/active7.1.3.gemfile
================================================
# This file was generated by Appraisal
source "https://rubygems.org"
gem "coveralls", :require => false
gem "rubocop", "~> 1.30.0", :require => false
gem "rubocop-performance", :require => false
gem "sqlite3"
gem "activesupport", "7.1.3"
gem "activerecord", "7.1.3"
gemspec :path => "../"
================================================
FILE: gemfiles/rails6.0.6.gemfile
================================================
# This file was generated by Appraisal
source "https://rubygems.org"
gem "coveralls", :require => false
gem "rubocop", "~> 1.30.0", :require => false
gem "rubocop-performance", :require => false
gem "sqlite3"
gem "rails", "6.0.6"
gem "rspec-rails"
gem "test-unit"
gemspec :path => "../"
================================================
FILE: gemfiles/rails6.1.7.6.gemfile
================================================
# This file was generated by Appraisal
source "https://rubygems.org"
gem "coveralls", :require => false
gem "rubocop", "~> 1.30.0", :require => false
gem "rubocop-performance", :require => false
gem "sqlite3"
gem "rails", "6.1.7.6"
gem "rspec-rails"
gem "test-unit"
gemspec :path => "../"
================================================
FILE: gemfiles/rails7.0.8.gemfile
================================================
# This file was generated by Appraisal
source "https://rubygems.org"
gem "coveralls", :require => false
gem "rubocop", "~> 1.30.0", :require => false
gem "rubocop-performance", :require => false
gem "sqlite3"
gem "rails", "7.0.8"
gem "rspec-rails"
gemspec :path => "../"
================================================
FILE: gemfiles/rails7.1.3.gemfile
================================================
# This file was generated by Appraisal
source "https://rubygems.org"
gem "coveralls", :require => false
gem "rubocop", "~> 1.30.0", :require => false
gem "rubocop-performance", :require => false
gem "sqlite3"
gem "rails", "7.1.3"
gem "rspec-rails"
gemspec :path => "../"
================================================
FILE: init.rb
================================================
# frozen_string_literal: true
require 'comma'
================================================
FILE: lib/comma/array.rb
================================================
# frozen_string_literal: true
class Array
def to_comma(style = :default)
Comma::Generator.new(self, style).run(:each)
end
end
================================================
FILE: lib/comma/data_extractor.rb
================================================
# frozen_string_literal: true
require 'comma/extractor'
module Comma
class DataExtractor < Extractor
class ExtractValueFromInstance
def initialize(instance)
@instance = instance
end
def extract(sym, &block)
yield_block_with_value(extract_value(sym), &block)
end
private
def yield_block_with_value(value, &block)
block ? yield(value) : value
end
def extract_value(method)
extraction_object.send(method)
end
def extraction_object
@instance
end
end
class ExtractValueFromAssociationOfInstance < ExtractValueFromInstance
def initialize(instance, association_name)
super(instance)
@association_name = association_name
end
private
def extraction_object
@instance.send(@association_name) || null_association
end
def null_association
@null_association ||= Class.new(Class.const_defined?(:BasicObject) ? ::BasicObject : ::Object) do
def method_missing(_symbol, *_args, &_block)
nil
end
end.new
end
end
def method_missing(sym, *args, &block)
@results << ExtractValueFromInstance.new(@instance).extract(sym, &block) if
args.blank?
args.each do |arg|
case arg
when Hash
arg.each do |k, _v|
@results << ExtractValueFromAssociationOfInstance.new(@instance, sym).extract(k, &block)
end
when Symbol
@results << ExtractValueFromAssociationOfInstance.new(@instance, sym).extract(arg, &block)
when String
@results << ExtractValueFromInstance.new(@instance).extract(sym, &block)
else
raise "Unknown data symbol #{arg.inspect}"
end
end
end
def __static_column__(_header = nil, &block)
@results << (block ? yield(@instance) : nil)
end
end
end
================================================
FILE: lib/comma/data_mapper_collection.rb
================================================
# frozen_string_literal: true
if defined?(DataMapper)
module DataMapper
class Collection
def to_comma(style = :default)
Comma::Generator.new(self, style).run(:each)
end
end
end
end
================================================
FILE: lib/comma/extractor.rb
================================================
# frozen_string_literal: true
module Comma
class Extractor
def initialize(instance, style, formats)
@instance = instance
@style = style
@formats = formats
@results = []
end
def results
instance_eval(&@formats[@style])
@results.map { |r| convert_to_data_value(r) }
end
def id(*args, &block)
method_missing(:id, *args, &block)
end
def __use__(style)
# TODO: prevent infinite recursion
instance_eval(&@formats[style])
end
private
def convert_to_data_value(result)
result.nil? ? result : result.to_s
end
end
end
================================================
FILE: lib/comma/generator.rb
================================================
# frozen_string_literal: true
module Comma
class Generator
def initialize(instance, style)
@instance = instance
@style = style
@options = {}
return unless @style.is_a?(Hash)
@options = @style.clone
@style = @options.delete(:style) || Comma::DEFAULT_OPTIONS[:style]
@filename = @options.delete(:filename)
end
def run(iterator_method)
if @filename
CSV_HANDLER.open(@filename, 'w', **@options) { |csv| append_csv(csv, iterator_method) } && (return true)
else
CSV_HANDLER.generate(**@options) { |csv| append_csv(csv, iterator_method) }
end
end
private
def append_csv(csv, iterator_method)
return '' if @instance.empty?
csv << @instance.first.to_comma_headers(@style) unless
@options.key?(:write_headers) && !@options[:write_headers]
@instance.send(iterator_method) do |object|
csv << object.to_comma(@style)
end
end
end
end
================================================
FILE: lib/comma/header_extractor.rb
================================================
# frozen_string_literal: true
require 'comma/extractor'
require 'active_support'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/date_time/conversions'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/inflections'
module Comma
class HeaderExtractor < Extractor
class_attribute :value_humanizer
DEFAULT_VALUE_HUMANIZER = lambda do |value, _model_class|
value.is_a?(String) ? value : value.to_s.humanize
end
self.value_humanizer = DEFAULT_VALUE_HUMANIZER
def method_missing(sym, *args, &_block)
model_class = @instance.class
@results << value_humanizer.call(sym, model_class) if args.blank?
args.each do |arg|
case arg
when Hash
arg.each do |_k, v|
@results << value_humanizer.call(v, get_association_class(model_class, sym))
end
when Symbol
@results << value_humanizer.call(arg, get_association_class(model_class, sym))
when String
@results << value_humanizer.call(arg, model_class)
else
raise "Unknown header symbol #{arg.inspect}"
end
end
end
def __static_column__(header = '', &_block)
@results << header
end
private
def get_association_class(model_class, association)
return unless model_class.respond_to?(:reflect_on_association)
begin
model_class.reflect_on_association(association)&.klass
rescue ArgumentError, NameError
# Since Rails 5.2, ArgumentError is raised.
nil
end
end
end
end
================================================
FILE: lib/comma/mongoid.rb
================================================
# frozen_string_literal: true
# Conditionally set to_comma on Mongoid records if mongoid gem is installed
begin
require 'mongoid'
module Mongoid
class Criteria
def to_comma(style = :default)
Comma::Generator.new(self, style).run(:each)
end
end
end
rescue LoadError => e
warn e.inspect
end
================================================
FILE: lib/comma/object.rb
================================================
# frozen_string_literal: true
require 'comma/data_extractor'
require 'comma/header_extractor'
class Object
class_attribute :comma_formats
class << self
def comma(style = :default, &block)
(self.comma_formats ||= {})[style] = block
end
def inherited(subclass)
super
subclass.comma_formats = self.comma_formats ? self.comma_formats.dup : {}
end
end
def to_comma(style = :default)
extract_with(Comma::DataExtractor, style)
end
def to_comma_headers(style = :default)
extract_with(Comma::HeaderExtractor, style)
end
private
def extract_with(extractor_class, style = :default)
raise_unless_style_exists(style)
extractor_class.new(self, style, self.comma_formats).results
end
def raise_unless_style_exists(style)
return if self.comma_formats && self.comma_formats[style]
raise "No comma format for class #{self.class} defined for style #{style}"
end
end
================================================
FILE: lib/comma/relation.rb
================================================
# frozen_string_literal: true
module ActiveRecord
class Relation
def to_comma(style = :default)
iterator_method =
if arel.ast.limit || !arel.ast.orders.empty?
Rails.logger.warn { <<~WARN } if defined?(Rails)
#to_comma is being used on a relation with limit or order clauses. Falling back to iterating with :each. This can cause performance issues.
WARN
:each
else
:find_each
end
Comma::Generator.new(self, style).run(iterator_method)
end
end
end
================================================
FILE: lib/comma/version.rb
================================================
# frozen_string_literal: true
module Comma
VERSION = '4.8.0'
end
================================================
FILE: lib/comma.rb
================================================
# frozen_string_literal: true
require 'csv'
CSV_HANDLER = CSV
module Comma
DEFAULT_OPTIONS = {
write_headers: true,
style: :default
}.freeze
end
require 'active_support'
require 'active_support/lazy_load_hooks'
ActiveSupport.on_load(:active_record) do
require 'comma/relation' if defined?(ActiveRecord::Relation)
end
ActiveSupport.on_load(:mongoid) do
require 'comma/mongoid'
end
require 'comma/data_mapper_collection' if defined? DataMapper
require 'comma/generator'
require 'comma/array'
require 'comma/object'
# Load into Rails controllers
ActiveSupport.on_load(:action_controller) do
if defined?(ActionController::Renderers) && ActionController::Renderers.respond_to?(:add)
ActionController::Renderers.add :csv do |obj, options|
filename = options[:filename] || 'data'
extension = options[:extension] || 'csv'
mime_type = if Rails.version >= '5.0.0'
options[:mime_type] || Mime[:csv]
else
options[:mime_type] || Mime::CSV
end
with_bom = options.delete(:with_bom) || false
# Capture any CSV optional settings passed to comma or comma specific options
csv_options = options.slice(*CSV_HANDLER::DEFAULT_OPTIONS.merge(Comma::DEFAULT_OPTIONS).keys)
csv_options = csv_options.each_with_object({}) do |(k, v), h|
# XXX: Convert string to boolean
h[k] = case k
when :write_headers
(v != 'false') if v.is_a?(String)
else
v
end
end
data = obj.to_comma(csv_options)
data = "\xEF\xBB\xBF#{data}" if with_bom
disposition = "attachment; filename=\"#{filename}.#{extension}\""
send_data data, type: mime_type, disposition: disposition
end
end
end
================================================
FILE: spec/comma/comma_spec.rb
================================================
# frozen_string_literal: true
require File.dirname(__FILE__) + '/../spec_helper'
describe Comma do
it 'should extend object to add a comma method' do
expect(Object).to respond_to(:comma)
end
it 'should extend object to have a to_comma method' do
expect(Object).to respond_to(:to_comma)
end
it 'should extend object to have a to_comma_headers method' do
expect(Object).to respond_to(:to_comma_headers)
end
describe '.to_comma_header' do
it 'should not crash (#94)' do
klass = Class.new
klass.instance_eval do
attr_accessor :name
comma :brief do
name
end
end
expect { klass.to_comma_headers(:brief) }.to_not raise_error
end
end
end
describe Comma, 'generating CSV' do # rubocop:disable Metrics/BlockLength
before do
@isbn = Isbn.new('123123123', '321321321')
@book = Book.new('Smalltalk-80', 'Language and Implementation', @isbn)
@books = []
@books << @book
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)
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")
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)
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)
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)
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)
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")
end
end
end
describe Comma, 'defining CSV descriptions' do
describe 'with an unnamed description' do
before do
class Foo
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
end
end
describe 'with a named description' do
before do
class Bar
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
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
attr_accessor :content
comma do; content; end
def initialize(content)
@content = content
end
end
@foo = Foo.new('content')
end
it 'should return and array of data content, using the :default CSV description if none requested' do
expect(@foo.to_comma).to eq(%w[content])
end
it 'should return and array of header content, using the :default CSV description if none requested' do
expect(@foo.to_comma_headers).to eq(%w[Content])
end
it 'should return the CSV representation including header and content when called on an array' do
expect(Array(@foo).to_comma).to eq("Content\ncontent\n")
end
end
describe 'with named descriptions' do
before do
class Foo
attr_accessor :content
comma :detailed do; content; end
def initialize(content)
@content = content
end
end
@foo = Foo.new('content')
end
it 'should return and array of data content, using the :default CSV description if none requested' do
expect(@foo.to_comma(:detailed)).to eq(%w[content])
end
it 'should return and array of header content, using the :default CSV description if none requested' do
expect(@foo.to_comma_headers(:detailed)).to eq(%w[Content])
end
it 'should return the CSV representation including header and content when called on an array' do
expect(Array(@foo).to_comma(:detailed)).to eq("Content\ncontent\n")
end
it 'should raise an error if the requested description is not avaliable' do
expect { @foo.to_comma(:bad) }.to raise_error(RuntimeError)
expect { @foo.to_comma_headers(:bad) }.to raise_error(RuntimeError)
expect { Array(@foo).to_comma(:bad) }.to raise_error(RuntimeError)
end
end
describe 'with block' do # rubocop:disable Metrics/BlockLength
before do
class Foo
attr_accessor :content, :created_at, :updated_at
comma do
content
content('Truncated Content') { |i| i && i.length > 10 ? i[0..10] : '---' }
created_at { |i| i&.to_formatted_s(:db) }
updated_at { |i| i&.to_formatted_s(:db) }
created_at 'Created Custom Label' do |i| i&.to_formatted_s(:short) end
updated_at 'Updated at Custom Label' do |i| i&.to_formatted_s(:short) end
end
def initialize(content, created_at = Time.now, updated_at = Time.now)
@content = content
@created_at = created_at
@updated_at = updated_at
end
end
@time = Time.now
@content = 'content ' * 5
@foo = Foo.new @content, @time, @time
end
it 'should return yielded values by block' do
_header, foo = Array(@foo).to_comma.split("\n")
expected = [
@content,
@content[0..10],
@time.to_formatted_s(:db),
@time.to_formatted_s(:db),
@time.to_formatted_s(:short),
@time.to_formatted_s(:short)
].join(',')
expect(foo).to eq(expected)
end
it 'should return headers with custom labels from block' do
header, _foo = Array(@foo).to_comma.split("\n")
expected = [
'Content',
'Truncated Content',
'Created at',
'Updated at',
'Created Custom Label',
'Updated at Custom Label'
].join(',')
expect(header).to eq(expected)
end
it 'should put headers in place when forced' do
header, _foo = Array(@foo).to_comma(write_headers: true).split("\n")
expected = [
'Content',
'Truncated Content',
'Created at',
'Updated at',
'Created Custom Label',
'Updated at Custom Label'
].join(',')
expect(header).to eq(expected)
end
it 'should not write headers if specified' do
header, _foo = Array(@foo).to_comma(write_headers: false).split("\n")
expected = [
@content,
@content[0..10],
@time.to_formatted_s(:db),
@time.to_formatted_s(:db),
@time.to_formatted_s(:short),
@time.to_formatted_s(:short)
].join(',')
expect(header).to eq(expected)
end
end
describe 'on an object with no comma declaration' do
it 'should raise an error mentioning there is no comma description defined for that class' do
expect { 'a string'.to_comma }.to raise_error('No comma format for class String defined for style default')
expect { 'a string'.to_comma_headers }
.to raise_error('No comma format for class String defined for style default')
end
end
describe 'on objects using Single Table Inheritance' do
before do
class MySuperClass
attr_accessor :content
comma do; content end
def initialize(content)
@content = 'super-' + content
end
end
class ChildClassComma < MySuperClass
comma do; content end
def initialize(content)
@content = 'sub-' + content
end
end
class ChildClassNoComma < MySuperClass
end
@childComma = ChildClassComma.new('content')
@childNoComma = ChildClassNoComma.new('content')
end
it 'should return and array of data content, as defined in comma block in child class' do
expect(@childComma.to_comma).to eq(%w[sub-content])
end
it 'should return and array of data content, as defined in comma block in super class, if not present in child' do
expect(@childNoComma.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
comma do
title
__use__ :description
end
comma :description do
__use__ :static
description
end
comma :static do
__static_column__ do 'Foo, Inc.' end
end
end.new(1, 'Programming Ruby', 'The Pickaxe book')
end
subject { @obj.to_comma }
its(:size) { should eq(3) }
it { should eq(['Programming Ruby', 'Foo, Inc.', 'The Pickaxe book']) }
end
================================================
FILE: spec/comma/data_extractor_spec.rb
================================================
# frozen_string_literal: true
require 'spec_helper'
# comma do
# name 'Title'
# description
#
# isbn :number_10 => 'ISBN-10', :number_13 => 'ISBN-13'
# end
describe Comma::DataExtractor do # rubocop:disable Metrics/BlockLength
before do
@isbn = Isbn.new('123123123', '321321321')
@book = Book.new('Smalltalk-80', 'Language and Implementation', @isbn)
@data = @book.to_comma
end
describe 'when no parameters are provided' do
it 'should use the string value returned by sending the method name on the object' do
expect(@data).to include('Language and Implementation')
end
end
describe 'when given a string description as a parameter' do
it 'should use the string value returned by sending the method name on the object' do
expect(@data).to include('Smalltalk-80')
end
end
describe 'when an hash is passed as a parameter' do
describe 'with a string value' do
it 'should use the string value, returned by sending the hash key to the object' do
expect(@data).to include('123123123')
expect(@data).to include('321321321')
end
it 'should not fail when an associated object is nil' do
expect { Book.new('Smalltalk-80', 'Language and Implementation', nil).to_comma }.not_to raise_error
end
end
end
end
describe Comma::DataExtractor, 'id attribute' do
before do
@data = Class.new(Struct.new(:id)) do
comma do
id 'ID' do |_id| '42' end
end
end.new(1).to_comma
end
it 'id attribute should yield block' do
expect(@data).to include('42')
end
end
describe Comma::DataExtractor, 'with static column method' do
before do
@data = Class.new(Struct.new(:id, :name)) do
comma do
__static_column__
__static_column__ 'STATIC'
__static_column__ 'STATIC' do '' end
__static_column__ 'STATIC', &:name
end
end.new(1, 'John Doe').to_comma
end
it 'should extract headers' do
expect(@data).to eq([nil, nil, '', 'John Doe'])
end
end
describe Comma::DataExtractor, 'nil value' do
before do
@data = Class.new(Struct.new(:id, :name)) do
comma do
name
name 'Name'
name 'Name' do |_name| nil end
end
end.new(1, nil).to_comma
end
it 'should extract nil' do
expect(@data).to eq([nil, nil, nil])
end
end
================================================
FILE: spec/comma/header_extractor_spec.rb
================================================
# frozen_string_literal: true
require 'spec_helper'
# comma do
# name 'Title'
# description
#
# isbn :number_10 => 'ISBN-10', :number_13 => 'ISBN-13'
# end
describe Comma::HeaderExtractor do # rubocop:disable Metrics/BlockLength
before do
@isbn = Isbn.new('123123123', '321321321')
@book = Book.new('Smalltalk-80', 'Language and Implementation', @isbn)
@headers = @book.to_comma_headers
end
describe 'when no parameters are provided' do
it 'should use the method name as the header name, humanized' do
expect(@headers).to include('Description')
end
end
describe 'when given a string description as a parameter' do
it 'should use the string value, unmodified' do
expect(@headers).to include('Title')
end
end
describe 'when an hash is passed as a parameter' do
describe 'with a string value' do
it 'should use the string value, unmodified' do
expect(@headers).to include('ISBN-10')
end
end
describe 'with a non-string value' do
it 'should use the non string value converted to a string, humanized' do
expect(@headers).to include('Issuer')
end
end
end
end
describe Comma::HeaderExtractor, 'with static column method' do
before do
@headers = Class.new(Struct.new(:id, :name)) do
comma do
__static_column__
__static_column__ 'STATIC'
__static_column__ 'STATIC' do '' end
end
end.new(1, 'John Doe').to_comma_headers
end
it 'should extract headers' do
expect(@headers).to eq(['', 'STATIC', 'STATIC'])
end
end
================================================
FILE: spec/comma/rails/active_record_spec.rb
================================================
# frozen_string_literal: true
require 'spec_helper'
if defined? ActiveRecord
describe Comma, 'generating CSV from an ActiveRecord object' do # rubocop:disable Metrics/BlockLength
class Picture < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
comma :pr_83 do
imageable name: 'Picture'
end
end
class Person < ActiveRecord::Base
scope(:teenagers, -> { where(age: 13..19) })
comma do
name
age
end
has_one :job
comma :issue_75 do
job :title
end
has_many :pictures, as: :imageable
end
class Job < ActiveRecord::Base
belongs_to :person
comma do
person_formatter name: 'Name'
end
def person_formatter
@person_formatter ||= PersonFormatter.new(person)
end
end
class PersonFormatter
def initialize(persor)
@person = persor
end
def name
@person.name
end
end
before(:all) do
# Setup AR model in memory
ActiveRecord::Base.connection.create_table :pictures, force: true do |table|
table.column :name, :string
table.column :imageable_id, :integer
table.column :imageable_type, :string
end
ActiveRecord::Base.connection.create_table :people, force: true do |table|
table.column :name, :string
table.column :age, :integer
end
Person.reset_column_information
ActiveRecord::Base.connection.create_table :jobs, force: true do |table|
table.column :person_id, :integer
table.column :title, :string
end
Job.reset_column_information
@person = Person.new(age: 18, name: 'Junior')
@person.build_job(title: 'Nice job')
@person.save!
Picture.create(name: 'photo.jpg', imageable_id: @person.id, imageable_type: 'Person')
end
describe '#to_comma on scopes' do
it 'should extend ActiveRecord::NamedScope::Scope to add a #to_comma method which will return CSV content for objects within the scope' do # rubocop:disable Layout/LineLength
expect(Person.teenagers.to_comma).to eq "Name,Age\nJunior,18\n"
end
it 'should find in batches' do
scope = Person.teenagers
expect(scope).to receive(:find_each).and_yield @person
scope.to_comma
end
it 'should fall back to iterating with each when scope has limit clause' do
scope = Person.limit(1)
expect(scope).to receive(:each).and_yield @person
scope.to_comma
end
it 'should fall back to iterating with each when scope has order clause' do
scope = Person.order(:age)
expect(scope).to receive(:each).and_yield @person
scope.to_comma
end
end
describe 'with custom value_humanizer' do
before do
Comma::HeaderExtractor.value_humanizer =
lambda do |value, model_class|
if model_class.respond_to?(:human_attribute_name)
model_class.human_attribute_name(value)
else
value.is_a?(String) ? value : value.to_s.humanize
end
end
I18n.config.backend.store_translations(:ja, activerecord: { attributes: { person: { age: '年齢', name: '名前' } } })
@original_locale = I18n.locale
I18n.locale = :ja
end
after do
I18n.locale = @original_locale
Comma::HeaderExtractor.value_humanizer =
Comma::HeaderExtractor::DEFAULT_VALUE_HUMANIZER
end
it 'should i18n-ize header values' do
expect(Person.teenagers.to_comma).to match(/^名前,年齢/)
end
end
describe 'github issue 75' do
it 'should find association' do
expect { Person.all.to_comma(:issue_75) }.not_to raise_error
end
end
describe 'with accessor' do
it 'should not raise exception' do
expect(Job.all.to_comma).to eq("Name\nJunior\n")
end
end
describe 'github pull-request 83' do
it 'should not raise NameError' do
expect { Picture.all.to_comma(:pr_83) }.not_to raise_error
end
end
end
describe Comma, 'generating CSV from an ActiveRecord object using Single Table Inheritance' do # rubocop:disable Metrics/BlockLength
class Animal < ActiveRecord::Base
comma do
name 'Name' do |name|
'Super-' + name
end
end
comma :with_type do
name
type
end
end
class Dog < Animal
comma do
name 'Name' do |name|
'Dog-' + name
end
end
end
class Cat < Animal
end
before(:all) do
# Setup AR model in memory
ActiveRecord::Base.connection.create_table :animals, force: true do |table|
table.column :name, :string
table.column :type, :string
end
@dog = Dog.new(name: 'Rex')
@dog.save!
@cat = Cat.new(name: 'Kitty')
@cat.save!
end
it 'should return and array of data content, as defined in comma block in child class' do
expect(@dog.to_comma).to eq %w[Dog-Rex]
end
# FIXME: this one is failing - the comma block from Dog is executed instead of the one from the super class
it 'should return and array of data content, as defined in comma block in super class, if not present in child' do
expect(@cat.to_comma).to eq %w[Super-Kitty]
end
it 'should call definion in parent class' do
expect { @dog.to_comma(:with_type) }.not_to raise_error
end
end
end
================================================
FILE: spec/comma/rails/data_mapper_collection_spec.rb
================================================
# frozen_string_literal: true
require 'spec_helper'
if defined? DataMapper
describe Comma, 'generating CSV from an DataMapper object' do # rubocop:disable Metrics/BlockLength
class Person
include DataMapper::Resource
property :id, Serial
property :name, String
property :age, Integer
def self.teenagers
all(:age.gte => 13) & all(:age.lte => 19)
end
comma do
name
age
end
end
DataMapper.finalize
before(:all) do
DataMapper.setup(:default, 'sqlite::memory:')
DataMapper.auto_migrate!
end
after(:all) do
end
describe 'case' do
before do
@person = Person.new(age: 18, name: 'Junior')
@person.save
end
it 'should extend scope to add a #to_comma method which will return CSV content for objects within the scope' do
Person.teenagers.to_comma.should == "Name,Age\nJunior,18\n"
end
it 'should find in batches' do
Person.teenagers.to_comma
end
end
end
end
================================================
FILE: spec/comma/rails/mongoid_spec.rb
================================================
# frozen_string_literal: true
require 'spec_helper'
if defined? Mongoid
describe Comma, 'generating CSV from an Mongoid object' do
class Person
include Mongoid::Document
field :name, type: String
field :age, type: Integer
scope :teenagers, between(age: 13..19)
comma do
name
age
end
end
after(:all) do
Mongoid.purge!
end
describe 'case' do
before do
@person = Person.new(age: 18, name: 'Junior')
@person.save
end
it 'should extend ActiveRecord::NamedScope::Scope to add a #to_comma method which will return CSV content for objects within the scope' do # rubocop:disable Layout/LineLength
Person.teenagers.to_comma.should == "Name,Age\nJunior,18\n"
end
it 'should find in batches' do
Person.teenagers.to_comma
end
end
end
end
================================================
FILE: spec/controllers/users_controller_spec.rb
================================================
# frozen_string_literal: true
require 'spec_helper'
if defined?(Rails)
RSpec.describe UsersController, type: :controller do # rubocop:disable Metrics/BlockLength
describe 'rails setup' do
it 'should capture the CSV renderer provided by Rails' do
mock_users = [mock_model(User), mock_model(User)]
allow(User).to receive(:all).and_return(mock_users)
expect(mock_users).to receive(:to_comma).once
get :index, format: :csv
end
end
describe 'controller' do # rubocop:disable Metrics/BlockLength
before(:all) do
@user_1 = User.create!(first_name: 'Fred', last_name: 'Flintstone')
@user_2 = User.create!(first_name: 'Wilma', last_name: 'Flintstone')
end
it 'should not affect html requested' do
get :index
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/html'
expect(response.body).to eq 'Users!'
end
it 'should return a csv when requested' do
get :index, format: :csv
expect(response.status).to eq 200
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
end
describe 'with comma options' do
it 'should allow the style to be chosen from the renderer' do
# Must be passed in same format (string/symbol) eg:
# format.csv { render User.all, :style => :shortened }
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
end
end
describe 'with custom options' do # rubocop:disable Metrics/BlockLength
def is_rails_4?
Rails::VERSION::STRING =~ /^4.*/
end
def get_(name, **args)
if is_rails_4? && args[:params]
args.merge!(args[:params])
args.delete(:params)
end
get name, **args
end
it 'should allow a filename to be set' do
get_ :with_custom_options, format: :csv, params: { custom_options: { filename: 'my_custom_name' } }
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/csv'
expect(response.header['Content-Disposition']).to include('filename="my_custom_name.csv"')
end
it 'should allow a custom filename with spaces' do
require 'shellwords'
params = { custom_options: { filename: 'filename with a lot of spaces' } }
get_ :with_custom_options, format: :csv, params: params
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/csv'
expect(response.header['Content-Disposition']).to include('filename="filename with a lot of spaces.csv"')
filename_string = response.header['Content-Disposition'].split('=').last
# shellsplit honors quoted strings
expect(filename_string.shellsplit.length).to eq 1
end
it 'should allow a file extension to be set' do
get_ :with_custom_options, format: :csv, params: { custom_options: { extension: :txt } }
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/csv'
expect(response.header['Content-Disposition']).to include('filename="data.txt"')
end
it 'should allow mime type to be set' do
get_ :with_custom_options, format: :csv, params: { custom_options: { mime_type: 'text/plain' } }
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/plain'
end
it 'should allow bom to be set' do
get_ :with_custom_options, format: :csv, params: { custom_options: { with_bom: true } }
expected_content = <<-CSV.gsub(/^\s+/, '')
\xEF\xBB\xBFFirst name,Last name,Name
Fred,Flintstone,Fred Flintstone
Wilma,Flintstone,Wilma Flintstone
CSV
expect(response.body). to eq expected_content
end
describe 'headers' do
it 'should allow toggling on' do
get_ :with_custom_options, format: :csv, params: { custom_options: { write_headers: 'true' } }
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
end
it 'should allow toggling off' do
get_ :with_custom_options, format: :csv, params: { custom_options: { write_headers: false } }
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/csv'
expected_content = <<-CSV.gsub(/^\s+/, '')
Fred,Flintstone,Fred Flintstone
Wilma,Flintstone,Wilma Flintstone
CSV
expect(response.body).to eq expected_content
end
end
it 'should allow forcing of quotes' do
get_ :with_custom_options, format: :csv, params: { custom_options: { force_quotes: true } }
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
end
it 'should allow combinations of options' do
params = {
custom_options: {
write_headers: false,
force_quotes: true,
col_sep: '||',
row_sep: "ENDOFLINE\n"
}
}
get_ :with_custom_options, format: :csv, params: params
expect(response.status).to eq 200
expect(response.media_type).to eq 'text/csv'
expected_content = <<-CSV.gsub(/^\s+/, '')
"Fred"||"Flintstone"||"Fred Flintstone"ENDOFLINE
"Wilma"||"Flintstone"||"Wilma Flintstone"ENDOFLINE
CSV
expect(response.body).to eq expected_content
end
end
end
end
end
================================================
FILE: spec/non_rails_app/ruby_classes.rb
================================================
# frozen_string_literal: true
class Book
attr_accessor :name, :description, :isbn
def initialize(name, description, isbn)
@name = name
@description = description
@isbn = isbn
end
comma do
name 'Title'
description
isbn authority: :issuer
isbn number_10: 'ISBN-10'
isbn number_13: 'ISBN-13'
end
comma :brief do
name
description
end
end
class Isbn
attr_accessor :number_10, :number_13
def initialize(isbn_10, isbn_13)
@number_10 = isbn_10
@number_13 = isbn_13
end
def authority
'ISBN'
end
end
================================================
FILE: spec/rails_app/active_record/config.rb
================================================
# frozen_string_literal: true
ActiveRecord::Base.configurations = { 'test' => { 'adapter' => 'sqlite3', 'database' => ':memory:' } }
ActiveRecord::Base.establish_connection(:test)
================================================
FILE: spec/rails_app/active_record/models.rb
================================================
# frozen_string_literal: true
class Post < ActiveRecord::Base
has_one :user
comma do
title
description
user :full_name
end
end
class User < ActiveRecord::Base
comma do
first_name
last_name
full_name 'Name'
end
comma :shortened do
first_name
last_name
end
def full_name
"#{first_name} #{last_name}".strip
end
end
class CreateTables < ActiveRecord::Migration[4.2]
def self.up
create_table :users do |t|
t.string :first_name
t.string :last_name
t.timestamps
end
create_table :posts do |t|
t.references :user
t.string :title
t.string :description
t.timestamps
end
end
def self.down
drop_table :posts
drop_table :users
end
end
ActiveRecord::Migration.verbose = false
CreateTables.up
================================================
FILE: spec/rails_app/data_mapper/config.rb
================================================
# frozen_string_literal: true
DataMapper.setup(:default, 'sqlite::memory:')
================================================
FILE: spec/rails_app/mongoid/config.rb
================================================
# frozen_string_literal: true
Mongoid.configure do |config|
config.sessions = {
default: {
hosts: ['localhost:27017'], database: 'comma_test'
}
}
end
================================================
FILE: spec/rails_app/rails_app.rb
================================================
# frozen_string_literal: true
require 'action_controller/railtie'
require 'action_view/railtie'
# orm configs
require 'rails_app/active_record/config' if defined?(ActiveRecord)
app = CommaTestApp = Class.new(Rails::Application)
app.config.secret_token = '6f6acf0443f74fd0aa8ff07a7c2fbe0a'
app.config.session_store :cookie_store, key: '_rails_app_session'
app.config.active_support.deprecation = :log
app.config.eager_load = false
app.config.root = File.dirname(__FILE__)
Rails.backtrace_cleaner.remove_silencers!
app.initialize!
app.routes.draw do
resources :users, only: [:index]
get 'with_custom_options', to: 'users#with_custom_options'
get 'with_custom_style', to: 'users#with_custom_style'
root to: 'users#index'
end
# models
require 'rails_app/active_record/models' if defined?(ActiveRecord)
def is_rails_4?
Rails::VERSION::STRING =~ /^4.*/
end
if is_rails_4?
def symbolize_param_keys(params)
params.symbolize_keys
end
else
def symbolize_param_keys(params)
if params
params.to_unsafe_h.symbolize_keys
else
{}
end
end
end
# controllers
class ApplicationController < ActionController::Base; end
class UsersController < ApplicationController
def index
respond_to do |format|
format.html do
if is_rails_4?
render text: 'Users!'
else
render plain: 'Users!'
end
end
format.csv { render csv: User.all }
end
end
def with_custom_options
render_options = { csv: User.all }.update(symbolize_param_keys(params[:custom_options]))
respond_to do |format|
format.csv { render render_options }
end
end
def with_custom_style
respond_to do |format|
format.csv { render csv: User.all, style: :shortened }
end
end
end
# helpers
Object.const_set(:ApplicationHelper, Module.new)
================================================
FILE: spec/rails_app/tmp/.gitkeep
================================================
================================================
FILE: spec/spec_helper.rb
================================================
# frozen_string_literal: true
require 'rubygems'
$LOAD_PATH.unshift(File.expand_path(File.join('..', '..', 'lib'), __FILE__))
require 'simplecov'
require 'coveralls'
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
if defined? Rails
SimpleCov.start('rails') do
add_filter %r{^/spec/comma/rails/data_mapper_collection_spec\.rb$}
add_filter %r{^/spec/comma/rails/mongoid_spec\.rb$}
end
else
SimpleCov.start do
add_filter %r{^/spec/comma/rails/data_mapper_collection_spec\.rb}
add_filter %r{^/spec/comma/rails/mongoid_spec\.rb}
add_filter %r{^/spec/controllers/}
end
end
require 'bundler/setup'
Bundler.require
require 'rspec/active_model/mocks'
require 'rspec/its'
begin
require 'rails'
rescue LoadError
warn 'rails not loaded'
end
%w[data_mapper mongoid active_record].each do |orm|
begin
require orm
break
rescue LoadError
warn "#{orm} not loaded"
end
end
if defined? Rails
require 'rails_app/rails_app'
require 'rspec/rails'
else
require 'rails_app/data_mapper/config' if defined?(DataMapper)
require 'rails_app/mongoid/config' if defined?(Mongoid)
require 'rails_app/active_record/config' if defined?(ActiveRecord)
end
Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |file| require file }
require File.expand_path('../spec/non_rails_app/ruby_classes', __dir__)
gitextract_uknkcqm5/
├── .coveralls.yml
├── .github/
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── .rubocop_todo.yml
├── .travis.yml
├── Appraisals
├── Gemfile
├── MIT-LICENSE
├── README.md
├── Rakefile
├── comma.gemspec
├── gemfiles/
│ ├── active6.0.6.gemfile
│ ├── active6.1.7.6.gemfile
│ ├── active7.0.8.gemfile
│ ├── active7.1.3.gemfile
│ ├── rails6.0.6.gemfile
│ ├── rails6.1.7.6.gemfile
│ ├── rails7.0.8.gemfile
│ └── rails7.1.3.gemfile
├── init.rb
├── lib/
│ ├── comma/
│ │ ├── array.rb
│ │ ├── data_extractor.rb
│ │ ├── data_mapper_collection.rb
│ │ ├── extractor.rb
│ │ ├── generator.rb
│ │ ├── header_extractor.rb
│ │ ├── mongoid.rb
│ │ ├── object.rb
│ │ ├── relation.rb
│ │ └── version.rb
│ └── comma.rb
└── spec/
├── comma/
│ ├── comma_spec.rb
│ ├── data_extractor_spec.rb
│ ├── header_extractor_spec.rb
│ └── rails/
│ ├── active_record_spec.rb
│ ├── data_mapper_collection_spec.rb
│ └── mongoid_spec.rb
├── controllers/
│ └── users_controller_spec.rb
├── non_rails_app/
│ └── ruby_classes.rb
├── rails_app/
│ ├── active_record/
│ │ ├── config.rb
│ │ └── models.rb
│ ├── data_mapper/
│ │ └── config.rb
│ ├── mongoid/
│ │ └── config.rb
│ ├── rails_app.rb
│ └── tmp/
│ └── .gitkeep
└── spec_helper.rb
SYMBOL INDEX (98 symbols across 19 files)
FILE: lib/comma.rb
type Comma (line 6) | module Comma
FILE: lib/comma/array.rb
class Array (line 3) | class Array
method to_comma (line 4) | def to_comma(style = :default)
FILE: lib/comma/data_extractor.rb
type Comma (line 5) | module Comma
class DataExtractor (line 6) | class DataExtractor < Extractor
class ExtractValueFromInstance (line 7) | class ExtractValueFromInstance
method initialize (line 8) | def initialize(instance)
method extract (line 12) | def extract(sym, &block)
method yield_block_with_value (line 18) | def yield_block_with_value(value, &block)
method extract_value (line 22) | def extract_value(method)
method extraction_object (line 26) | def extraction_object
class ExtractValueFromAssociationOfInstance (line 31) | class ExtractValueFromAssociationOfInstance < ExtractValueFromInstance
method initialize (line 32) | def initialize(instance, association_name)
method extraction_object (line 39) | def extraction_object
method null_association (line 43) | def null_association
method method_missing (line 52) | def method_missing(sym, *args, &block)
method __static_column__ (line 72) | def __static_column__(_header = nil, &block)
FILE: lib/comma/data_mapper_collection.rb
type DataMapper (line 4) | module DataMapper
class Collection (line 5) | class Collection
method to_comma (line 6) | def to_comma(style = :default)
FILE: lib/comma/extractor.rb
type Comma (line 3) | module Comma
class Extractor (line 4) | class Extractor
method initialize (line 5) | def initialize(instance, style, formats)
method results (line 12) | def results
method id (line 17) | def id(*args, &block)
method __use__ (line 21) | def __use__(style)
method convert_to_data_value (line 28) | def convert_to_data_value(result)
FILE: lib/comma/generator.rb
type Comma (line 3) | module Comma
class Generator (line 4) | class Generator
method initialize (line 5) | def initialize(instance, style)
method run (line 17) | def run(iterator_method)
method append_csv (line 27) | def append_csv(csv, iterator_method)
FILE: lib/comma/header_extractor.rb
type Comma (line 10) | module Comma
class HeaderExtractor (line 11) | class HeaderExtractor < Extractor
method method_missing (line 19) | def method_missing(sym, *args, &_block)
method __static_column__ (line 38) | def __static_column__(header = '', &_block)
method get_association_class (line 44) | def get_association_class(model_class, association)
FILE: lib/comma/mongoid.rb
type Mongoid (line 7) | module Mongoid
class Criteria (line 8) | class Criteria
method to_comma (line 9) | def to_comma(style = :default)
FILE: lib/comma/object.rb
class Object (line 6) | class Object
method comma (line 10) | def comma(style = :default, &block)
method inherited (line 14) | def inherited(subclass)
method to_comma (line 20) | def to_comma(style = :default)
method to_comma_headers (line 24) | def to_comma_headers(style = :default)
method extract_with (line 30) | def extract_with(extractor_class, style = :default)
method raise_unless_style_exists (line 35) | def raise_unless_style_exists(style)
FILE: lib/comma/relation.rb
type ActiveRecord (line 3) | module ActiveRecord
class Relation (line 4) | class Relation
method to_comma (line 5) | def to_comma(style = :default)
FILE: lib/comma/version.rb
type Comma (line 3) | module Comma
FILE: spec/comma/comma_spec.rb
class Foo (line 92) | class Foo
method initialize (line 126) | def initialize(content)
method initialize (line 153) | def initialize(content)
method initialize (line 193) | def initialize(content, created_at = Time.now, updated_at = Time.now)
class Bar (line 105) | class Bar
class Foo (line 122) | class Foo
method initialize (line 126) | def initialize(content)
method initialize (line 153) | def initialize(content)
method initialize (line 193) | def initialize(content, created_at = Time.now, updated_at = Time.now)
class Foo (line 149) | class Foo
method initialize (line 126) | def initialize(content)
method initialize (line 153) | def initialize(content)
method initialize (line 193) | def initialize(content, created_at = Time.now, updated_at = Time.now)
class Foo (line 182) | class Foo
method initialize (line 126) | def initialize(content)
method initialize (line 153) | def initialize(content)
method initialize (line 193) | def initialize(content, created_at = Time.now, updated_at = Time.now)
class MySuperClass (line 268) | class MySuperClass
method initialize (line 272) | def initialize(content)
class ChildClassComma (line 277) | class ChildClassComma < MySuperClass
method initialize (line 280) | def initialize(content)
class ChildClassNoComma (line 285) | class ChildClassNoComma < MySuperClass
FILE: spec/comma/rails/active_record_spec.rb
class Picture (line 8) | class Picture < ActiveRecord::Base
class Person (line 16) | class Person < ActiveRecord::Base
class Job (line 33) | class Job < ActiveRecord::Base
method person_formatter (line 40) | def person_formatter
class PersonFormatter (line 45) | class PersonFormatter
method initialize (line 46) | def initialize(persor)
method name (line 50) | def name
class Animal (line 153) | class Animal < ActiveRecord::Base
class Dog (line 166) | class Dog < Animal
class Cat (line 174) | class Cat < Animal
FILE: spec/comma/rails/data_mapper_collection_spec.rb
class Person (line 8) | class Person
method teenagers (line 15) | def self.teenagers
FILE: spec/comma/rails/mongoid_spec.rb
class Person (line 8) | class Person
FILE: spec/controllers/users_controller_spec.rb
function is_rails_4? (line 67) | def is_rails_4?
function get_ (line 71) | def get_(name, **args)
FILE: spec/non_rails_app/ruby_classes.rb
class Book (line 3) | class Book
method initialize (line 6) | def initialize(name, description, isbn)
class Isbn (line 27) | class Isbn
method initialize (line 30) | def initialize(isbn_10, isbn_13)
method authority (line 35) | def authority
FILE: spec/rails_app/active_record/models.rb
class Post (line 3) | class Post < ActiveRecord::Base
class User (line 14) | class User < ActiveRecord::Base
method full_name (line 26) | def full_name
class CreateTables (line 31) | class CreateTables < ActiveRecord::Migration[4.2]
method up (line 32) | def self.up
method down (line 47) | def self.down
FILE: spec/rails_app/rails_app.rb
function is_rails_4? (line 28) | def is_rails_4?
function symbolize_param_keys (line 33) | def symbolize_param_keys(params)
function symbolize_param_keys (line 37) | def symbolize_param_keys(params)
class ApplicationController (line 47) | class ApplicationController < ActionController::Base; end
class UsersController (line 48) | class UsersController < ApplicationController
method index (line 49) | def index
method with_custom_options (line 62) | def with_custom_options
method with_custom_style (line 70) | def with_custom_style
Condensed preview — 48 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (62K chars).
[
{
"path": ".coveralls.yml",
"chars": 24,
"preview": "service_name: travis-ci\n"
},
{
"path": ".github/workflows/build.yml",
"chars": 831,
"preview": "name: Build\non: [push, pull_request]\njobs:\n build:\n strategy:\n matrix:\n ruby: ['3.0', '3.1', '3.2', '3.3"
},
{
"path": ".gitignore",
"chars": 106,
"preview": "pkg/*\n.*.swp\n*~\n.bundle\nspec/rails_app/log\nspec/rails_app/db/development.sqlite*\n.rbx/\n.ruby-*\ncoverage/*\n"
},
{
"path": ".rspec",
"chars": 9,
"preview": "--colour\n"
},
{
"path": ".rubocop.yml",
"chars": 352,
"preview": "inherit_from: .rubocop_todo.yml\n\nrequire: rubocop-performance\n\nAllCops:\n DisplayCopNames: true\n Exclude:\n - 'gemfil"
},
{
"path": ".rubocop_todo.yml",
"chars": 4536,
"preview": "# This configuration was generated by\n# `rubocop --auto-gen-config`\n# on 2024-01-20 09:02:51 UTC using RuboCop version 1"
},
{
"path": ".travis.yml",
"chars": 1081,
"preview": "sudo: false\n\nservices: mongodb\n\nlanguage: ruby\ncache: bundler\nrvm:\n - 2.4.10\n - 2.5.8\n - 2.6.6\n - 2.7.2\ngemfile:\n -"
},
{
"path": "Appraisals",
"chars": 736,
"preview": "# frozen_string_literal: true\n\nappraise 'rails6.0.6' do\n gem 'rails', '6.0.6'\n gem 'rspec-rails'\n gem 'test-unit'\nend"
},
{
"path": "Gemfile",
"chars": 202,
"preview": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n\ngemspec\n\ngem 'coveralls', require: false\ngem 'rubocop', '~"
},
{
"path": "MIT-LICENSE",
"chars": 1058,
"preview": "Copyright (c) 2009 Marcus Crafter\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this "
},
{
"path": "README.md",
"chars": 1738,
"preview": "# Comma\n\nA library to generate comma seperated value (CSV) for Ruby objects like ActiveRecord and Array\n\n[![Gem Version]"
},
{
"path": "Rakefile",
"chars": 281,
"preview": "# frozen_string_literal: true\n\nrequire 'bundler/setup'\nrequire 'bundler/gem_tasks'\n\nrequire 'rspec/core/rake_task'\nRSpec"
},
{
"path": "comma.gemspec",
"chars": 1041,
"preview": "# frozen_string_literal: true\n\n$LOAD_PATH.push File.expand_path('lib', __dir__)\nrequire 'comma/version'\n\nGem::Specificat"
},
{
"path": "gemfiles/active6.0.6.gemfile",
"chars": 292,
"preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"coveralls\", :require => false\ngem \"rubocop\","
},
{
"path": "gemfiles/active6.1.7.6.gemfile",
"chars": 296,
"preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"coveralls\", :require => false\ngem \"rubocop\","
},
{
"path": "gemfiles/active7.0.8.gemfile",
"chars": 292,
"preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"coveralls\", :require => false\ngem \"rubocop\","
},
{
"path": "gemfiles/active7.1.3.gemfile",
"chars": 292,
"preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"coveralls\", :require => false\ngem \"rubocop\","
},
{
"path": "gemfiles/rails6.0.6.gemfile",
"chars": 290,
"preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"coveralls\", :require => false\ngem \"rubocop\","
},
{
"path": "gemfiles/rails6.1.7.6.gemfile",
"chars": 292,
"preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"coveralls\", :require => false\ngem \"rubocop\","
},
{
"path": "gemfiles/rails7.0.8.gemfile",
"chars": 274,
"preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"coveralls\", :require => false\ngem \"rubocop\","
},
{
"path": "gemfiles/rails7.1.3.gemfile",
"chars": 274,
"preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"coveralls\", :require => false\ngem \"rubocop\","
},
{
"path": "init.rb",
"chars": 47,
"preview": "# frozen_string_literal: true\n\nrequire 'comma'\n"
},
{
"path": "lib/comma/array.rb",
"chars": 135,
"preview": "# frozen_string_literal: true\n\nclass Array\n def to_comma(style = :default)\n Comma::Generator.new(self, style).run(:e"
},
{
"path": "lib/comma/data_extractor.rb",
"chars": 1933,
"preview": "# frozen_string_literal: true\n\nrequire 'comma/extractor'\n\nmodule Comma\n class DataExtractor < Extractor\n class Extra"
},
{
"path": "lib/comma/data_mapper_collection.rb",
"chars": 214,
"preview": "# frozen_string_literal: true\n\nif defined?(DataMapper)\n module DataMapper\n class Collection\n def to_comma(style"
},
{
"path": "lib/comma/extractor.rb",
"chars": 622,
"preview": "# frozen_string_literal: true\n\nmodule Comma\n class Extractor\n def initialize(instance, style, formats)\n @instan"
},
{
"path": "lib/comma/generator.rb",
"chars": 1031,
"preview": "# frozen_string_literal: true\n\nmodule Comma\n class Generator\n def initialize(instance, style)\n @instance = inst"
},
{
"path": "lib/comma/header_extractor.rb",
"chars": 1614,
"preview": "# frozen_string_literal: true\n\nrequire 'comma/extractor'\nrequire 'active_support'\nrequire 'active_support/core_ext/class"
},
{
"path": "lib/comma/mongoid.rb",
"chars": 327,
"preview": "# frozen_string_literal: true\n\n# Conditionally set to_comma on Mongoid records if mongoid gem is installed\nbegin\n requi"
},
{
"path": "lib/comma/object.rb",
"chars": 939,
"preview": "# frozen_string_literal: true\n\nrequire 'comma/data_extractor'\nrequire 'comma/header_extractor'\n\nclass Object\n class_att"
},
{
"path": "lib/comma/relation.rb",
"chars": 547,
"preview": "# frozen_string_literal: true\n\nmodule ActiveRecord\n class Relation\n def to_comma(style = :default)\n iterator_me"
},
{
"path": "lib/comma/version.rb",
"chars": 68,
"preview": "# frozen_string_literal: true\n\nmodule Comma\n VERSION = '4.8.0'\nend\n"
},
{
"path": "lib/comma.rb",
"chars": 1821,
"preview": "# frozen_string_literal: true\n\nrequire 'csv'\nCSV_HANDLER = CSV\n\nmodule Comma\n DEFAULT_OPTIONS = {\n write_headers: tr"
},
{
"path": "spec/comma/comma_spec.rb",
"chars": 10343,
"preview": "# frozen_string_literal: true\n\nrequire File.dirname(__FILE__) + '/../spec_helper'\n\ndescribe Comma do\n it 'should extend"
},
{
"path": "spec/comma/data_extractor_spec.rb",
"chars": 2357,
"preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\n# comma do\n# name 'Title'\n# description\n#\n# isbn :number_10 "
},
{
"path": "spec/comma/header_extractor_spec.rb",
"chars": 1586,
"preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\n# comma do\n# name 'Title'\n# description\n#\n# isbn :number_10 "
},
{
"path": "spec/comma/rails/active_record_spec.rb",
"chars": 5524,
"preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nif defined? ActiveRecord\n\n describe Comma, 'generating CSV from a"
},
{
"path": "spec/comma/rails/data_mapper_collection_spec.rb",
"chars": 1050,
"preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nif defined? DataMapper\n\n describe Comma, 'generating CSV from an "
},
{
"path": "spec/comma/rails/mongoid_spec.rb",
"chars": 889,
"preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nif defined? Mongoid\n\n describe Comma, 'generating CSV from an Mon"
},
{
"path": "spec/controllers/users_controller_spec.rb",
"chars": 6719,
"preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nif defined?(Rails)\n\n RSpec.describe UsersController, type: :contr"
},
{
"path": "spec/non_rails_app/ruby_classes.rb",
"chars": 574,
"preview": "# frozen_string_literal: true\n\nclass Book\n attr_accessor :name, :description, :isbn\n\n def initialize(name, description"
},
{
"path": "spec/rails_app/active_record/config.rb",
"chars": 181,
"preview": "# frozen_string_literal: true\n\nActiveRecord::Base.configurations = { 'test' => { 'adapter' => 'sqlite3', 'database' => '"
},
{
"path": "spec/rails_app/active_record/models.rb",
"chars": 825,
"preview": "# frozen_string_literal: true\n\nclass Post < ActiveRecord::Base\n has_one :user\n\n comma do\n title\n description\n\n "
},
{
"path": "spec/rails_app/data_mapper/config.rb",
"chars": 77,
"preview": "# frozen_string_literal: true\n\nDataMapper.setup(:default, 'sqlite::memory:')\n"
},
{
"path": "spec/rails_app/mongoid/config.rb",
"chars": 169,
"preview": "# frozen_string_literal: true\n\nMongoid.configure do |config|\n config.sessions = {\n default: {\n hosts: ['localho"
},
{
"path": "spec/rails_app/rails_app.rb",
"chars": 1837,
"preview": "# frozen_string_literal: true\n\nrequire 'action_controller/railtie'\nrequire 'action_view/railtie'\n\n# orm configs\nrequire "
},
{
"path": "spec/rails_app/tmp/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "spec/spec_helper.rb",
"chars": 1345,
"preview": "# frozen_string_literal: true\n\nrequire 'rubygems'\n$LOAD_PATH.unshift(File.expand_path(File.join('..', '..', 'lib'), __FI"
}
]
About this extraction
This page contains the full source code of the comma-csv/comma GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 48 files (55.7 KB), approximately 16.7k tokens, and a symbol index with 98 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.