diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..95ba194 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,56 @@ +# Copilot instructions for `comma` + +## Build, test, and lint commands + +This repository is a Ruby gem. Ruby 3.0+ is required, and the CI matrix exercises Ruby 3.0-3.4 against Rails/ActiveRecord appraisals from 6.0 through 7.1. + +```sh +# install dependencies for the base Gemfile +bundle install + +# install all appraisal Gemfiles used by CI +bundle exec appraisal install + +# build the gem +bundle exec rake build + +# lint +bundle exec rubocop -P +# or +bundle exec rake rubocop + +# base test suite (runs non-Rails specs when framework gems are absent) +bundle exec rspec spec +# or +bundle exec rake spec + +# run one example from the base suite +bundle exec rspec spec/comma/comma_spec.rb:205 + +# run the full multi-gemfile matrix locally +bundle exec appraisal rake spec + +# run a single spec file under a specific appraisal +bundle exec appraisal active7.1.3 bundle exec rspec spec/comma/rails/active_record_spec.rb + +# CI equivalent for a single matrix entry +BUNDLE_GEMFILE=gemfiles/rails7.1.3.gemfile bundle exec rspec spec/controllers/users_controller_spec.rb +``` + +## High-level architecture + +- `lib/comma/object.rb` adds the core DSL globally via `Object.comma`. Each class stores named format blocks in `comma_formats`, and subclasses inherit a shallow copy of those formats. +- `lib/comma/extractor.rb` is the shared execution engine. It `instance_eval`s a stored format block and collects stringified results. The two concrete extractors split responsibilities: + - `lib/comma/data_extractor.rb` resolves values from the instance or an associated object and applies optional block-based transformations. + - `lib/comma/header_extractor.rb` derives headers from the same DSL and can map association columns to the associated model class for humanized labels. +- `lib/comma/generator.rb` is the only place that turns object rows into CSV output. `Array`, `ActiveRecord::Relation`, `Mongoid::Criteria`, and `DataMapper::Collection` each delegate to it from their own extension files. +- `lib/comma.rb` wires framework integrations lazily with `ActiveSupport.on_load`. That file is also where the Rails `render csv:` renderer is registered, so controller behavior is part of the gem's load path rather than test-only glue. +- Integration specs use the miniature app under `spec/rails_app/` plus inline model definitions inside spec files. The base suite still runs without Rails, Mongoid, DataMapper, or ActiveRecord because integration examples are wrapped in `if defined?(...)` guards in the specs. + +## Key conventions + +- The CSV DSL is method-call driven. Inside a `comma` block, a bare method adds one column, a string argument overrides the header label, and symbol/hash arguments traverse associations. The same block definition drives both headers and row data. +- Style composition uses `__use__ :style_name`, and computed/static columns use `__static_column__`. Preserve those internal DSL entry points when changing extractor behavior. +- Header labels default to `HeaderExtractor.value_humanizer`, which is mutable global state. Specs that override it reset it afterward; follow the same pattern for any future changes. +- `ActiveRecord::Relation#to_comma` intentionally uses `find_each` only for unordered, unlimited relations. If a relation has `limit` or `order`, it falls back to `each`; when Rails is loaded it also emits a warning instead of forcing batched iteration. +- Specs commonly define throwaway classes inline to document DSL behavior instead of introducing fixtures or helper classes. Prefer extending the existing focused examples in `spec/comma/*` unless a change genuinely needs the Rails test app. diff --git a/README.md b/README.md index 216aba1..9a66c0f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Comma -A library to generate comma seperated value (CSV) for Ruby objects like ActiveRecord and Array +A library for generating comma-separated values (CSV) from Ruby objects, arrays, and supported ORM collections. [![Gem Version](https://badge.fury.io/rb/comma.svg)](http://badge.fury.io/rb/comma) [![Build Status](https://github.com/comma-csv/comma/actions/workflows/build.yml/badge.svg)](https://github.com/comma-csv/comma/actions/workflows/build.yml) [![Code Climate](https://codeclimate.com/github/comma-csv/comma.svg)](https://codeclimate.com/github/comma-csv/comma) @@ -8,7 +8,9 @@ A library to generate comma seperated value (CSV) for Ruby objects like ActiveRe ### 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. +You need Ruby 3.0 or later. + +For Rails / ActiveRecord integration, this repository is currently tested against ActiveRecord and Rails 6.0 through 7.1 on Ruby 3.0 through 3.4. ### Installing @@ -17,33 +19,111 @@ Comma is distributed as a gem, best installed via Bundler. Include the gem in your Gemfile: ```ruby -gem 'comma', '~> 4.8.0' +gem 'comma', '~> 4.9.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' +gem 'comma', git: 'https://github.com/comma-csv/comma.git' ``` Then, run `bundle install`. ### Usage -See [this page](https://github.com/comma-csv/comma/wiki) for usages. +Define a CSV format on your object with `comma`. Calling `to_comma` on a single object returns the row values, while calling it on an array or supported collection generates CSV output: + +```ruby +class User + attr_reader :first_name, :last_name + + def initialize(first_name, last_name) + @first_name = first_name + @last_name = last_name + end + + comma do + first_name + last_name + full_name 'Name' + end + + def full_name + "#{first_name} #{last_name}".strip + end +end + +user = User.new('Ada', 'Lovelace') +user.to_comma +# => ["Ada", "Lovelace", "Ada Lovelace"] + +users = [User.new('Ada', 'Lovelace'), User.new('Grace', 'Hopper')] +users.to_comma +# => "First name,Last name,Name\nAda,Lovelace,Ada Lovelace\nGrace,Hopper,Grace Hopper\n" +``` + +You can also define named styles and select them when generating CSV: + +```ruby +class User + comma :short do + first_name + last_name + end +end + +users.to_comma(:short) +``` + +In Rails controllers, requiring the gem registers `render csv:` support: + +```ruby +def index + render csv: User.all +end +``` + +See the [wiki](https://github.com/comma-csv/comma/wiki) for more usage examples. ## 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: +Install dependencies: ```sh -$ bundle exec appraisal install -$ bundle exec appraisal rake spec +bundle install +bundle exec appraisal install +``` + +Run the default test suite and linter: +```sh +bundle exec rspec spec +bundle exec rubocop -P +``` + +Run a single example: + +```sh +bundle exec rspec spec/comma/comma_spec.rb:205 +``` + +To run the test suite across the Rails / ActiveRecord gemfile matrix, this repository uses [Appraisal](https://github.com/thoughtbot/appraisal): + +```sh +bundle exec appraisal rake spec +``` + +You can also run a specific spec under one appraisal: + +```sh +bundle exec appraisal rails7.1.3 bundle exec rspec spec/controllers/users_controller_spec.rb ``` ## Contributing +Please make sure `bundle exec rspec spec`, `bundle exec rubocop -P`, and any relevant `bundle exec appraisal ...` commands pass before opening a pull request. + ## 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). @@ -56,4 +136,4 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available, ## 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. +This project is licensed under the MIT License - see the [MIT-LICENSE](https://github.com/comma-csv/comma/blob/master/MIT-LICENSE) file for details.