thamble 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 151f04c20fd4fb3d9bc6d0d014abe94424beaa13
4
+ data.tar.gz: ebf84e54eb74d67aa190d7799a5f7d2359bbef6d
5
+ SHA512:
6
+ metadata.gz: 8f18301bfd0ceffe9e2fdafd6f9f4f66c7b40b7c8ad72023906820061bfca39fd79f5ef52d709fd10642386cf9add244ee876789bc16b481d24f9c1111aa1843
7
+ data.tar.gz: ec63ac38947321bf99a5452da6c248248f1bcab1744b4b80391a5b07da0342c23a8d7f95889c474a5d775e75a801bb5c3ed20f23c5b6798a37ca8913c85ac831
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ === 1.0.0 (2014-01-07)
2
+
3
+ * Initial Public Release
data/MIT-LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2013 Jeremy Evans
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,100 @@
1
+ = Thamble
2
+
3
+ Thamble exposes a single method, table, for easily creating HTML
4
+ tables from enumerable objects.
5
+
6
+ = Installation
7
+
8
+ sudo gem install thamble
9
+
10
+ = Source Code
11
+
12
+ Source code is available on GitHub at https://github.com/jeremyevans/thamble
13
+
14
+ = Examples
15
+
16
+ The default behavior just expects an enumerable of arrays (such as an array of
17
+ arrays), and returns a string containing the HTML TABLE output:
18
+
19
+ puts Thamble.table([[1, 2]])
20
+
21
+ <table>
22
+ <tbody>
23
+ <tr>
24
+ <td>1</td>
25
+ <td>2</td>
26
+ </tr>
27
+ </tbody>
28
+ </table>
29
+
30
+ If a block is passed to the method, all items in the enumerable are yielded to
31
+ the block, and the block should return an array with the data to use in the table:
32
+
33
+ puts Thamble.table([{:a=>1, :b=>2}, {:a=>3, :b=>4}]){|l| [l[:b], l[:a] + 10]}
34
+
35
+ <table>
36
+ <tbody>
37
+ <tr>
38
+ <td>2</td>
39
+ <td>11</td>
40
+ </tr>
41
+ <tr>
42
+ <td>4</td>
43
+ <td>13</td>
44
+ </tr>
45
+ </tbody>
46
+ </table>
47
+
48
+ You can use the :headers option to set custom headers:
49
+
50
+ puts Thamble.table([[1, 2], [3, 4]], :headers=>['A', 'B'])
51
+
52
+ <table>
53
+ <thead>
54
+ <tr>
55
+ <th>A</th>
56
+ <th>B</th>
57
+ </tr>
58
+ </thead>
59
+ <tbody>
60
+ <tr>
61
+ <td>1</td>
62
+ <td>2</td>
63
+ </tr>
64
+ <tr>
65
+ <td>3</td>
66
+ <td>4</td>
67
+ </tr>
68
+ </tbody>
69
+ </table>
70
+
71
+ Other options supported are:
72
+
73
+ :caption :: A caption for the table
74
+ :table :: HTML attribute hash for the table itself
75
+ :td :: HTML attribute hash for the table data cells, can be a proc called
76
+ with the data value, row position, and row that returns a hash
77
+ :th :: HTML attribute hash for the table header cells, can be a proc called
78
+ with the header that returns a hash
79
+ :tr :: HTML attribute hash for the table rows, can be a proc called with
80
+ the row that returns a hash
81
+ :widths :: Array of widths for each column
82
+
83
+ = Rails Support
84
+
85
+ Thamble comes with basic rails support via:
86
+
87
+ require 'thamble/rails'
88
+ ApplicationController.helper Thamble::RailsHelper
89
+
90
+ This allows you to use the following style in your templates:
91
+
92
+ <%= thamble([[1, 2], [3, 4]], :headers=>['A', 'B']) %>
93
+
94
+ = License
95
+
96
+ MIT
97
+
98
+ = Author
99
+
100
+ Jeremy Evans <code@jeremyevans.net>
data/Rakefile ADDED
@@ -0,0 +1,69 @@
1
+ require "rake"
2
+ require "rake/clean"
3
+
4
+ CLEAN.include ["thamble-*.gem", "rdoc", "coverage"]
5
+
6
+ desc "Build thamble gem"
7
+ task :package=>[:clean] do |p|
8
+ sh %{#{FileUtils::RUBY} -S gem build thamble.gemspec}
9
+ end
10
+
11
+ ### Specs
12
+
13
+ begin
14
+ begin
15
+ # RSpec 1
16
+ require "spec/rake/spectask"
17
+ spec_class = Spec::Rake::SpecTask
18
+ spec_files_meth = :spec_files=
19
+ rescue LoadError
20
+ # RSpec 2
21
+ require "rspec/core/rake_task"
22
+ spec_class = RSpec::Core::RakeTask
23
+ spec_files_meth = :pattern=
24
+ end
25
+
26
+ spec = lambda do |name, files, d|
27
+ lib_dir = File.join(File.dirname(File.expand_path(__FILE__)), 'lib')
28
+ ENV['RUBYLIB'] ? (ENV['RUBYLIB'] += ":#{lib_dir}") : (ENV['RUBYLIB'] = lib_dir)
29
+ desc d
30
+ spec_class.new(name) do |t|
31
+ t.send(spec_files_meth, files)
32
+ end
33
+ end
34
+
35
+ task :default => [:spec]
36
+ spec.call("spec", Dir["spec/*_spec.rb"], "Run specs")
37
+ rescue LoadError
38
+ task :default do
39
+ puts "Must install rspec to run the default task (which runs specs)"
40
+ end
41
+ end
42
+
43
+ ### RDoc
44
+
45
+ RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Thamble: Create HTML Tables from Enumerables']
46
+
47
+ begin
48
+ gem 'rdoc', '= 3.12.2'
49
+ gem 'hanna-nouveau'
50
+ RDOC_DEFAULT_OPTS.concat(['-f', 'hanna'])
51
+ rescue Gem::LoadError
52
+ end
53
+
54
+ rdoc_task_class = begin
55
+ require "rdoc/task"
56
+ RDoc::Task
57
+ rescue LoadError
58
+ require "rake/rdoctask"
59
+ Rake::RDocTask
60
+ end
61
+
62
+ RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
63
+
64
+ rdoc_task_class.new do |rdoc|
65
+ rdoc.rdoc_dir = "rdoc"
66
+ rdoc.options += RDOC_OPTS
67
+ rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/**/*.rb"
68
+ end
69
+
data/lib/thamble.rb ADDED
@@ -0,0 +1,207 @@
1
+ require 'rack/utils'
2
+
3
+ # Thamble exposes a single method named table to make it easy to generate
4
+ # an HTML table from an enumerable.
5
+ module Thamble
6
+ # Empty frozen hash used for default option hashes
7
+ OPTS = {}.freeze
8
+
9
+ # Return a string containing an HTML table representing the data from the
10
+ # enumerable. +enum+ should be an enumerable containing the data. If a block
11
+ # is given, it is yielded each element in +enum+, and should return an array
12
+ # representing the table data to use for that row.
13
+ #
14
+ # Options:
15
+ #
16
+ # :headers :: The headers to use for the table, as an array of strings or a
17
+ # single string using commas as the separtor.
18
+ # :caption :: A caption for the table
19
+ # :table :: HTML attribute hash for the table itself
20
+ # :td :: HTML attribute hash for the table data cells, can be a proc called
21
+ # with the data value, row position, and row that returns a hash
22
+ # :th :: HTML attribute hash for the table header cells, can be a proc called
23
+ # with the header that returns a hash
24
+ # :tr :: HTML attribute hash for the table rows, can be a proc called with
25
+ # the row that returns a hash
26
+ # :widths :: An array of widths to use for each column
27
+ def table(enum, opts=OPTS)
28
+ t = Table.new(opts)
29
+ enum.each do |row|
30
+ row = yield(row, t) if block_given?
31
+ t << row
32
+ end
33
+ t.to_s
34
+ end
35
+ module_function :table
36
+
37
+ # The Table class stores the rows and attributes to use for the HTML tags,
38
+ # and contains helper methods for common formatting.
39
+ class Table
40
+ # Create a new Table instance. Usually not called directly,
41
+ # but through Thamble.table.
42
+ def initialize(opts=OPTS)
43
+ @opts = opts
44
+ @rows = []
45
+ end
46
+
47
+ # Add a row to the table.
48
+ def <<(row)
49
+ @rows << row
50
+ end
51
+
52
+ # Return a string containing the HTML table.
53
+ def to_s
54
+ empty = ''.freeze
55
+ tr = 'tr'.freeze
56
+ th = 'th'.freeze
57
+ td = 'td'.freeze
58
+ nl = "\n".freeze
59
+ tr_attr = @opts[:tr]
60
+ th_attr = @opts[:th]
61
+ td_attr = @opts[:td]
62
+
63
+ t = tag('table', empty, @opts[:table])
64
+ s = t.open
65
+ s << nl
66
+
67
+ if caption = @opts[:caption]
68
+ s << tag(:caption, caption).to_s
69
+ end
70
+
71
+ if widths = @opts[:widths]
72
+ s << "<colgroup>\n"
73
+ widths.each do |w|
74
+ s << "<col width=\"#{w.to_i}\" />\n"
75
+ end
76
+ s << "</colgroup>\n"
77
+ end
78
+
79
+ if headers = @opts[:headers]
80
+ s << "<thead>\n"
81
+ headers = headers.split(',') if headers.is_a?(String)
82
+ trh = tag(tr, empty, handle_proc(tr_attr, headers))
83
+ s << trh.open
84
+ s << nl
85
+ headers.each_with_index do |header, i|
86
+ s << tag(th, header, handle_proc(th_attr, header)).to_s
87
+ end
88
+ s << trh.close
89
+ s << "</thead>\n"
90
+ end
91
+
92
+ s << "<tbody>\n"
93
+ @rows.each do |row|
94
+ trh = tag(tr, empty, handle_proc(tr_attr, row))
95
+ s << trh.open
96
+ s << nl
97
+ row.each_with_index do |col, i|
98
+ s << tag(td, col, handle_proc(td_attr, col, i, row)).to_s
99
+ end
100
+ s << trh.close
101
+ end
102
+ s << "</tbody>\n"
103
+ s << t.close
104
+ end
105
+
106
+ # Create a Tag object from the arguments.
107
+ def tag(*a)
108
+ Tag.tag(*a)
109
+ end
110
+
111
+ # Create an a tag with the given text and href.
112
+ def a(text, href, opts=OPTS)
113
+ tag('a', text, opts.merge(:href=>href))
114
+ end
115
+
116
+ # Return a Raw string, which won't be HTML escaped.
117
+ def raw(s)
118
+ RawString.new(s)
119
+ end
120
+
121
+ private
122
+
123
+ # If pr is a Proc or Method, call it with the given arguments,
124
+ # otherwise return it directly.
125
+ def handle_proc(pr, *a)
126
+ case pr
127
+ when Proc, Method
128
+ pr.call(*a)
129
+ else
130
+ pr
131
+ end
132
+ end
133
+ end
134
+
135
+ # Module that can be included into other String subclasses so
136
+ # that the instances are not HTML escaped
137
+ module Raw
138
+ end
139
+
140
+ # Simple subclass of string, where instances are not HTML
141
+ # escaped.
142
+ class RawString < String
143
+ include Raw
144
+ end
145
+
146
+ # Tags represent an individual HTML tag.
147
+ class Tag
148
+ # The type of the tag
149
+ attr_reader :type
150
+
151
+ # If the given content is already a Tag instance with the
152
+ # same type, return it directly, otherwise create a new
153
+ # Tag instance with the given arguments.
154
+ def self.tag(type, content='', attr=nil)
155
+ if content.is_a?(Tag) && content.type.to_s == type.to_s
156
+ content
157
+ else
158
+ new(type, content, attr)
159
+ end
160
+ end
161
+
162
+ # Create a new instance. Usually not called
163
+ # directly, but through Tag.tag.
164
+ def initialize(type, content='', attr=nil)
165
+ @type, @content, @attr = type, content, attr||OPTS
166
+ end
167
+
168
+ # A string for the HTML to use for this tag.
169
+ def to_s
170
+ "#{open}#{content}#{close}"
171
+ end
172
+
173
+ # A string for the opening HTML for the tag.
174
+ def open
175
+ "<#{@type}#{' ' unless @attr.empty?}#{attr}>"
176
+ end
177
+
178
+ # A string for the inner HTML for the tag.
179
+ def content
180
+ h @content
181
+ end
182
+
183
+ # A string for the closing HTML for the tag.
184
+ def close
185
+ "</#{@type}>\n"
186
+ end
187
+
188
+ private
189
+
190
+ # A string for the html attributes for the tag.
191
+ def attr
192
+ @attr.map{|k,v| "#{k}=\"#{h v}\""}.sort.join(' ')
193
+ end
194
+
195
+ # A HTML-escaped version of the given argument.
196
+ def h(s)
197
+ case s
198
+ when Raw
199
+ s
200
+ when Tag
201
+ s.to_s
202
+ else
203
+ Rack::Utils.escape_html(s.to_s)
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,11 @@
1
+ require 'thamble'
2
+ require 'active_support/core_ext/string/output_safety'
3
+ ActiveSupport::SafeBuffer.send(:include, Thamble::Raw)
4
+
5
+ module Thamble
6
+ module RailsHelper
7
+ def thamble(*a, &block)
8
+ raw Thamble.table(*a, &block)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,87 @@
1
+ require 'rubygems'
2
+ require File.join(File.dirname(File.expand_path(__FILE__)), '../lib/thamble')
3
+
4
+ if defined?(RSpec)
5
+ require 'rspec/version'
6
+ if RSpec::Version::STRING >= '2.11.0'
7
+ RSpec.configure do |config|
8
+ config.expect_with :rspec do |c|
9
+ c.syntax = :should
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ describe "Thamble.table" do
16
+ def table(*a, &block)
17
+ Thamble.table(*a, &block).gsub(/\s+\n/m, '').gsub("\n", '')
18
+ end
19
+
20
+ it 'should return string with HTML table for enumerable' do
21
+ table([[1, 2]]).should == '<table><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
22
+ end
23
+
24
+ it 'should support :headers option for the headers' do
25
+ table([[1, 2]], :headers=>%w'a b').should == '<table><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
26
+ end
27
+
28
+ it 'should support :headers option as a string with comma separators' do
29
+ table([[1, 2]], :headers=>'a,b').should == '<table><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
30
+ end
31
+
32
+ it 'should support :widths option for setting width for each column' do
33
+ table([[1, 2]], :widths=>[3,4]).should == '<table><colgroup><col width="3" /><col width="4" /></colgroup><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
34
+ end
35
+
36
+ it 'should yield each object in enumerable to block to return data row to use' do
37
+ table([[1, 2]]){|l, t| l.map{|i| i*2}}.should == '<table><tbody><tr><td>2</td><td>4</td></tr></tbody></table>'
38
+ end
39
+
40
+ it 'should be able to create tags using the table.tag method' do
41
+ table([[1, 2]]){|l, t| l.map{|i| t.tag(:b, i*2)}}.should == '<table><tbody><tr><td><b>2</b></td><td><b>4</b></td></tr></tbody></table>'
42
+ table([[1, 2]]){|l, t| l.map{|i| t.tag(:b, i*2, i=>i)}}.should == '<table><tbody><tr><td><b 1="1">2</b></td><td><b 2="2">4</b></td></tr></tbody></table>'
43
+ end
44
+
45
+ it 'should be able to create links using the table.a method' do
46
+ table([[1, 2]]){|l, t| l.map{|i| t.a(i*2, 'foo')}}.should == '<table><tbody><tr><td><a href="foo">2</a></td><td><a href="foo">4</a></td></tr></tbody></table>'
47
+ table([[1, 2]]){|l, t| l.map{|i| t.a(i*2, 'foo', i=>i)}}.should == '<table><tbody><tr><td><a 1="1" href="foo">2</a></td><td><a 2="2" href="foo">4</a></td></tr></tbody></table>'
48
+ end
49
+
50
+ it 'should support :table option for the table attribtues' do
51
+ table([[1, 2]], :table=>{:class=>'foo'}).should == '<table class="foo"><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
52
+ end
53
+
54
+ it 'should support :tr option for the tr attributes' do
55
+ table([[1, 2]], :tr=>{:class=>'foo'}).should == '<table><tbody><tr class="foo"><td>1</td><td>2</td></tr></tbody></table>'
56
+ table([[1, 2]], :headers=>%w'a b', :tr=>{:class=>'foo'}).should == '<table><thead><tr class="foo"><th>a</th><th>b</th></tr></thead><tbody><tr class="foo"><td>1</td><td>2</td></tr></tbody></table>'
57
+ end
58
+
59
+ it 'should support :td option for the td attributes' do
60
+ table([[1, 2]], :td=>{:class=>'foo'}).should == '<table><tbody><tr><td class="foo">1</td><td class="foo">2</td></tr></tbody></table>'
61
+ end
62
+
63
+ it 'should support :th option for the th attributes' do
64
+ table([[1, 2]], :headers=>%w'a b', :th=>{:class=>'foo'}).should == '<table><thead><tr><th class="foo">a</th><th class="foo">b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
65
+ end
66
+
67
+ it 'should support a proc for the :tr option' do
68
+ table([[1, 2]], :tr=>proc{|row| {:class=>"foo#{row.join}"}}).should == '<table><tbody><tr class="foo12"><td>1</td><td>2</td></tr></tbody></table>'
69
+ table([[1, 2]], :headers=>%w'a b', :tr=>proc{|row| {:class=>"foo#{row.join}"}}).should == '<table><thead><tr class="fooab"><th>a</th><th>b</th></tr></thead><tbody><tr class="foo12"><td>1</td><td>2</td></tr></tbody></table>'
70
+ end
71
+
72
+ it 'should support a proc for the :td option' do
73
+ table([[1, 2]], :td=>proc{|v, i, row| {:class=>"foo#{row.join}-#{v}-#{i}"}}).should == '<table><tbody><tr><td class="foo12-1-0">1</td><td class="foo12-2-1">2</td></tr></tbody></table>'
74
+ end
75
+
76
+ it 'should support a proc for the :th option' do
77
+ table([[1, 2]], :headers=>%w'a b', :th=>proc{|v| {:class=>"foo#{v}"}}).should == '<table><thead><tr><th class="fooa">a</th><th class="foob">b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
78
+ end
79
+
80
+ it 'should support :caption option for the table caption' do
81
+ table([[1, 2]], :headers=>%w'a b', :caption=>'Foo').should == '<table><caption>Foo</caption><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
82
+ end
83
+
84
+ it 'should be callable as a method if including the module' do
85
+ Class.new{include Thamble}.new.send(:table, [[1, 2]]).gsub(/\s+\n/m, '').gsub("\n", '').should == '<table><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'
86
+ end
87
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thamble
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Evans
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: |
28
+ Thamble exposes a single method, table, for easily creating HTML
29
+ tables from enumerable objects.
30
+ email: code@jeremyevans.net
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files:
34
+ - README.rdoc
35
+ - CHANGELOG
36
+ - MIT-LICENSE
37
+ files:
38
+ - MIT-LICENSE
39
+ - CHANGELOG
40
+ - README.rdoc
41
+ - Rakefile
42
+ - spec/thamble_spec.rb
43
+ - lib/thamble.rb
44
+ - lib/thamble/rails.rb
45
+ homepage: http://gihub.com/jeremyevans/thamble
46
+ licenses:
47
+ - MIT
48
+ metadata: {}
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --quiet
52
+ - --line-numbers
53
+ - --inline-source
54
+ - --title
55
+ - 'Thamble: Create HTML Tables from Enumerables'
56
+ - --main
57
+ - README.rdoc
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project:
72
+ rubygems_version: 2.0.14
73
+ signing_key:
74
+ specification_version: 4
75
+ summary: Create HTML Tables from Enumerables
76
+ test_files: []