comma 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Marcus Crafter
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,132 @@
1
+ = COMMA
2
+
3
+ [http://github.com/crafterm/comma](http://github.com/crafterm/comma)
4
+
5
+ == DESCRIPTION:
6
+
7
+ Comma is a CSV (ie. comma separated values) generation extension for Ruby objects, that lets you seamlessly define a CSV output format via a small DSL. Comma works well on pure Ruby objects with attributes, as well as complex ones such as ActiveRecord objects with associations, extensions, etc. It doesn't distinguish between attributes, methods, associations, extensions, etc - they all are considered equal and invoked identically via the Comma DSL description. Multiple different CSV output descriptions can also be defined.
8
+
9
+ When multiple objects in an Array are converted to CSV, the output includes generation of a header row reflected from names of the properties requested, or specified via the DSL.
10
+
11
+ CSV can be a bit of a boring format - the motivation behind Comma was to have a CSV extension that was simple, flexible, and would treat attributes, methods, associations, etc, all the same without the need for any complex configuration, and also work on Ruby objects, not just ActiveRecord or other base class derivatives.
12
+
13
+ An example Comma CSV enabled ActiveRecord class:
14
+
15
+ class Book < ActiveRecord::Base
16
+
17
+ # ================
18
+ # = Associations =
19
+ # ================
20
+ has_many :pages
21
+ has_one :isbn
22
+ belongs_to :publisher
23
+
24
+ # ===============
25
+ # = CSV support =
26
+ # ===============
27
+ comma do
28
+
29
+ name
30
+ description
31
+
32
+ pages :size => 'Pages'
33
+ publisher :name
34
+ isbn :number_10 => 'ISBN-10', :number_13 => 'ISBN-13'
35
+ blurb 'Summary'
36
+
37
+ end
38
+
39
+ end
40
+
41
+ Annotated, the comma description is as follows:
42
+
43
+ # starts a Comma description block, generating 2 methods #to_comma and #to_comma_headers for this class.
44
+ comma do
45
+
46
+ # name, description are attributes of Book with the header being reflected as 'Name', 'Description'
47
+ name
48
+ description
49
+
50
+ # pages is an association returning an array, :size is called on the association results, with the header name specifed as 'Pages'
51
+ pages :size => 'Pages'
52
+
53
+ # publisher is an association returning an object, :name is called on the associated object, with the reflected header 'Name'
54
+ publisher :name
55
+
56
+ # isbn is an association returning an object, :number_10 and :number_13 are called on the object with the specified headers 'ISBN-10' and 'ISBN-13'
57
+ isbn :number_10 => 'ISBN-10', :number_13 => 'ISBN-13'
58
+
59
+ # blurb is an attribute of Book, with the header being specified directly as 'Summary'
60
+ blurb 'Summary'
61
+
62
+ end
63
+
64
+ In the above example, any of the declarations (name, description, pages, publisher, isbn, blurb, etc), could be methods, attributes, associations, etc - no distinction during configuration is required, as everything is invoked via Ruby's #send method.
65
+
66
+ You can get the CSV representation of any object by calling the to_comma method, optionally providing a CSV description name to use.
67
+
68
+ Object values are automatically converted to strings via to_s allowing you to reuse any existing to_s methods on your objects (instead of having to call particular properties or define CSV specific output methods). Header names are also automatically humanized when reflected (eg. replacing _ characters with whitespace). The 'isbn' example above shows how multiple values can be added to the CSV output.
69
+
70
+ Multiple CSV descriptions can also be specified for the same class, eg:
71
+
72
+ class Book < ActiveRecord::Base
73
+
74
+ # ================
75
+ # = Associations =
76
+ # ================
77
+ has_many :pages
78
+ has_one :isbn
79
+ belongs_to :publisher
80
+
81
+ # ===============
82
+ # = CSV support =
83
+ # ===============
84
+ comma do
85
+
86
+ name
87
+ description
88
+
89
+ pages :size => 'Pages'
90
+ publisher :name
91
+ isbn :number_10 => 'ISBN-10', :number_13 => 'ISBN-13'
92
+ blurb 'Summary'
93
+
94
+ end
95
+
96
+ comma :brief do
97
+
98
+ name
99
+ description
100
+ blurb 'Summary'
101
+
102
+ end
103
+
104
+ end
105
+
106
+ You can specify which output format you would like to use via an optional parameter to to_comma:
107
+
108
+ Book.limited(10).to_comma(:brief)
109
+
110
+ Specifying no description name to to_comma is equivalent to specifying :default as the description name.
111
+
112
+ You can pass options for FasterCVS, e.g.
113
+
114
+ Book.limited(10).to_comma(:style => :brief, :col_sep => ';', :force_quotes => true)
115
+
116
+ When used with Rails (ie. add 'comma' as a gem dependency), Comma automatically adds support for rendering CSV output in your controllers:
117
+
118
+ class BooksController < ApplicationController
119
+
120
+ def index
121
+ respond_to do |format|
122
+ format.csv { render :csv => Book.limited(50) }
123
+ end
124
+ end
125
+
126
+ end
127
+
128
+ If you have any questions or suggestions for Comma, please feel free to contact me at crafterm@redartisan.com, all feedback welcome!
129
+
130
+ == DEPENDENCIES
131
+
132
+ If you're on ruby 1.8.*, you'll need to have the fastercsv gem installed
@@ -0,0 +1,68 @@
1
+ require 'activesupport'
2
+ require 'comma/extractors'
3
+
4
+ if RUBY_VERSION =~ /^1.9/
5
+ require 'csv'
6
+ FasterCSV = CSV
7
+ else
8
+ require 'fastercsv'
9
+ end
10
+
11
+ class Array
12
+ def to_comma(style = :default)
13
+ options = {}
14
+
15
+ if style.is_a? Hash
16
+ options = style
17
+ style = options.delete(:style)||:default
18
+ end
19
+
20
+ FasterCSV.generate(options) do |csv|
21
+ return "" if empty?
22
+ csv << first.to_comma_headers(style) # REVISIT: request to optionally include headers
23
+ each do |object|
24
+ csv << object.to_comma(style)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ class Object
31
+ class_inheritable_accessor :comma_formats
32
+
33
+ def self.comma(style = :default, &block)
34
+ (self.comma_formats ||= {})[style] = block
35
+ end
36
+
37
+ def to_comma(style = :default)
38
+ raise "No comma format for class #{self.class} defined for style #{style}" unless self.comma_formats and self.comma_formats[style]
39
+ Comma::DataExtractor.new(self, &self.comma_formats[style]).results
40
+ end
41
+
42
+ def to_comma_headers(style = :default)
43
+ raise "No comma format for class #{self.class} defined for style #{style}" unless self.comma_formats and self.comma_formats[style]
44
+ Comma::HeaderExtractor.new(self, &self.comma_formats[style]).results
45
+ end
46
+ end
47
+
48
+ if defined?(ActionController)
49
+ module RenderAsCSV
50
+
51
+ def self.included(base)
52
+ base.send :include, InstanceMethods
53
+ base.alias_method_chain :render, :csv
54
+ end
55
+
56
+ module InstanceMethods
57
+ def render_with_csv(options = nil, extra_options = {}, &block)
58
+ return render_without_csv(options, extra_options, &block) unless options.is_a?(Hash) and options[:csv]
59
+ data = options.delete(:csv)
60
+ style = options.delete(:style) || :default
61
+ send_data Array(data).to_comma(style), options.merge(:type => :csv)
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ ActionController::Base.send :include, RenderAsCSV
68
+ end
@@ -0,0 +1,75 @@
1
+ module Comma
2
+
3
+ class Extractor
4
+
5
+ def initialize(instance, &block)
6
+ @instance = instance
7
+ @block = block
8
+ @results = []
9
+ end
10
+
11
+ def results
12
+ instance_eval &@block
13
+ @results
14
+ end
15
+
16
+ def id(*args)
17
+ method_missing(:id, *args)
18
+ end
19
+ end
20
+
21
+ class HeaderExtractor < Extractor
22
+
23
+ def method_missing(sym, *args, &block)
24
+ @results << sym.to_s.humanize if args.blank?
25
+
26
+ args.each do |arg|
27
+ case arg
28
+ when Hash
29
+ arg.each do |k, v|
30
+ @results << ((v.is_a? String) ? v : v.to_s.humanize)
31
+ end
32
+ when Symbol
33
+ @results << arg.to_s.humanize
34
+ when String
35
+ @results << arg
36
+ else
37
+ raise "Unknown header symbol #{arg.inspect}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ class DataExtractor < Extractor
44
+
45
+ def method_missing(sym, *args, &block)
46
+ if args.blank?
47
+ result = block ? yield(@instance.send(sym)) : @instance.send(sym)
48
+ @results << result.to_s
49
+ end
50
+
51
+ args.each do |arg|
52
+ case arg
53
+ when Hash
54
+ arg.each do |k, v|
55
+ if block
56
+ @results << (@instance.send(sym).nil? ? '' : yield(@instance.send(sym).send(k)).to_s )
57
+ else
58
+ @results << (@instance.send(sym).nil? ? '' : @instance.send(sym).send(k).to_s )
59
+ end
60
+ end
61
+ when Symbol
62
+ if block
63
+ @results << (@instance.send(sym).nil? ? '' : yield(@instance.send(sym).send(arg)).to_s)
64
+ else
65
+ @results << ( @instance.send(sym).nil? ? '' : @instance.send(sym).send(arg).to_s )
66
+ end
67
+ when String
68
+ @results << (block ? yield(@instance.send(sym)) : @instance.send(sym)).to_s
69
+ else
70
+ raise "Unknown data symbol #{arg.inspect}"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: comma
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Marcus Crafter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-09 00:00:00 +11:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: fastercsv
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.4.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.2.2
34
+ version:
35
+ description:
36
+ email: crafterm@redartisan.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - README.markdown
45
+ - MIT-LICENSE
46
+ - lib/comma.rb
47
+ - lib/comma/extractors.rb
48
+ has_rdoc: true
49
+ homepage: http://github.com/crafterm/comma
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options: []
54
+
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.3.5
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Ruby Comma Seperated Values generation library
76
+ test_files: []
77
+