thamble 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []