sequel-reporter 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +66 -0
- data/Rakefile +5 -0
- data/bin/sequel-reporter +13 -0
- data/data/Gemfile +10 -0
- data/data/Rakefile.tt +10 -0
- data/data/application.rb.tt +17 -0
- data/data/config.ru +3 -0
- data/data/lib/.gitkeep +0 -0
- data/data/migrate/.gitkeep +0 -0
- data/data/public/.gitkeep +0 -0
- data/data/public/css/bootstrap.css +6307 -0
- data/data/public/css/bootstrap.min.css +873 -0
- data/data/public/img/glyphicons-halflings-white.png +0 -0
- data/data/public/img/glyphicons-halflings.png +0 -0
- data/data/public/js/bootstrap.js +2279 -0
- data/data/public/js/bootstrap.min.js +7 -0
- data/data/public/js/jquery-1.9.1.js +9597 -0
- data/data/views/error.erb +5 -0
- data/data/views/layout.erb +60 -0
- data/data/views/reports/dashboard.erb +5 -0
- data/data/views/table.erb +31 -0
- data/lib/sequel-reporter/application.rb +51 -0
- data/lib/sequel-reporter/cli.rb +28 -0
- data/lib/sequel-reporter/helpers.rb +52 -0
- data/lib/sequel-reporter/report.rb +171 -0
- data/lib/sequel-reporter/version.rb +5 -0
- data/lib/sequel-reporter.rb +11 -0
- data/sequel-reporter.gemspec +25 -0
- data/test/report_spec.rb +63 -0
- data/test/spec_helper.rb +16 -0
- metadata +161 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Sequel::Reporter</title>
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7
|
+
<meta name="description" content="">
|
8
|
+
<meta name="author" content="">
|
9
|
+
|
10
|
+
<link href="/css/bootstrap.css" rel="stylesheet">
|
11
|
+
<style>
|
12
|
+
body {
|
13
|
+
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
14
|
+
}
|
15
|
+
</style>
|
16
|
+
|
17
|
+
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
|
18
|
+
<!--[if lt IE 9]>
|
19
|
+
<script src="../assets/js/html5shiv.js"></script>
|
20
|
+
<![endif]-->
|
21
|
+
</head>
|
22
|
+
|
23
|
+
<body>
|
24
|
+
|
25
|
+
<div class="navbar navbar-inverse navbar-fixed-top">
|
26
|
+
<div class="navbar-inner">
|
27
|
+
<div class="container">
|
28
|
+
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
29
|
+
<span class="icon-bar"></span>
|
30
|
+
<span class="icon-bar"></span>
|
31
|
+
<span class="icon-bar"></span>
|
32
|
+
</button>
|
33
|
+
<a class="brand" href="/">Sequel::Reporter</a>
|
34
|
+
<div class="nav-collapse collapse">
|
35
|
+
<ul class="nav">
|
36
|
+
<li class="dropdown">
|
37
|
+
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
38
|
+
Reports
|
39
|
+
<b class="caret"></b>
|
40
|
+
</a>
|
41
|
+
<ul class="dropdown-menu">
|
42
|
+
<% @reports.each do |report| %>
|
43
|
+
<li><a href="/reports/<%= report[0] %>"><%= report[1] %></a></li>
|
44
|
+
<% end %>
|
45
|
+
</ul>
|
46
|
+
</li>
|
47
|
+
</ul>
|
48
|
+
</div><!--/.nav-collapse -->
|
49
|
+
</div>
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
<div class="container">
|
54
|
+
<%= yield %>
|
55
|
+
</div> <!-- /container -->
|
56
|
+
|
57
|
+
<script src="/js/jquery-1.9.1.js"></script>
|
58
|
+
<script src="/js/bootstrap.js"></script>
|
59
|
+
</body>
|
60
|
+
</html>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<% if report.error %>
|
2
|
+
<div class="alert-message block-message warning">
|
3
|
+
<p><%= report.error %></p>
|
4
|
+
<% if report.error.to_s != "No data" %>
|
5
|
+
<p><%= report.error.backtrace %></p>
|
6
|
+
<% end %>
|
7
|
+
</div>
|
8
|
+
<% else %>
|
9
|
+
<table class="table table-striped table-borderd table-hover table-condensed sorted">
|
10
|
+
<thead>
|
11
|
+
<tr>
|
12
|
+
<% report.fields.each do |f| %>
|
13
|
+
<th><span class="<%= f.span_class %>"><%= f.title %></span></th>
|
14
|
+
<% end %>
|
15
|
+
</tr>
|
16
|
+
</thead>
|
17
|
+
<tbody>
|
18
|
+
<% report.each_row do |row| %>
|
19
|
+
<tr>
|
20
|
+
<% row.each do |val| %>
|
21
|
+
<td>
|
22
|
+
<span class="<%= val[1].span_class %>">
|
23
|
+
<%= linkify(links, row, val, (val[1].value_type == 'number' && ! val[0].nil?) ? sprintf("%0.2f", val[0]) : val[0]) %>
|
24
|
+
</span>
|
25
|
+
</td>
|
26
|
+
<% end %>
|
27
|
+
</tr>
|
28
|
+
<% end %>
|
29
|
+
</tbody>
|
30
|
+
</table>
|
31
|
+
<% end %>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/contrib'
|
3
|
+
require 'sequel'
|
4
|
+
|
5
|
+
module Sequel::Reporter
|
6
|
+
class Application < Sinatra::Base
|
7
|
+
|
8
|
+
helpers Sinatra::Capture
|
9
|
+
helpers Sequel::Reporter::Helpers
|
10
|
+
|
11
|
+
set :render_engine, :erb
|
12
|
+
set :database_url, ENV['DATABASE_URL']
|
13
|
+
|
14
|
+
attr_reader :db
|
15
|
+
|
16
|
+
before do
|
17
|
+
Sequel::Reporter::Report.params = params
|
18
|
+
|
19
|
+
@reports = []
|
20
|
+
Dir.glob(File.join(settings.root, "views", "reports", "*")).each do |report|
|
21
|
+
name = File.basename(report, File.extname(report))
|
22
|
+
@reports << [name, name.capitalize]
|
23
|
+
end
|
24
|
+
@reports = @reports.sort {|a,b| a[0] <=> b[0]}
|
25
|
+
end
|
26
|
+
|
27
|
+
get '/' do
|
28
|
+
index_report = settings.index_report
|
29
|
+
redirect "/reports/#{index_report.to_s}"
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/*' do
|
33
|
+
begin
|
34
|
+
render settings.render_engine, params[:splat][0].to_sym
|
35
|
+
rescue Exception => e
|
36
|
+
@error = e
|
37
|
+
render :erb, :error
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(app=nil)
|
42
|
+
@db = Sequel.connect(self.class.settings.database_url)
|
43
|
+
|
44
|
+
path = File.join(settings.root, "lib", "**", "*.rb")
|
45
|
+
Dir.glob(path).each do |file|
|
46
|
+
require file
|
47
|
+
end
|
48
|
+
super(app)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Sequel::Reporter
|
4
|
+
class CLI < Thor
|
5
|
+
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
desc "new NAME","Create a new Sequel::Reporter project"
|
9
|
+
def new(name)
|
10
|
+
@name = name
|
11
|
+
|
12
|
+
empty_directory(name)
|
13
|
+
self.destination_root = name
|
14
|
+
copy_file("Gemfile")
|
15
|
+
template("Rakefile.tt", "Rakefile")
|
16
|
+
template("application.rb.tt", "application.rb")
|
17
|
+
template("config.ru")
|
18
|
+
directory("lib")
|
19
|
+
directory("migrate")
|
20
|
+
directory("public")
|
21
|
+
directory("views")
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.source_root
|
25
|
+
File.expand_path("../../../data", __FILE__)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
module Sequel::Reporter
|
5
|
+
module Helpers
|
6
|
+
|
7
|
+
include Rack::Utils
|
8
|
+
|
9
|
+
def partial(template, locals = {})
|
10
|
+
render_engine = locals.delete(:render_engine) || settings.render_engine
|
11
|
+
render render_engine, template, :layout => false, :locals => locals
|
12
|
+
end
|
13
|
+
|
14
|
+
def table(report, options = {})
|
15
|
+
links = options[:links] || {}
|
16
|
+
partial(:table, :report => report, :links => links, :render_engine => :erb)
|
17
|
+
end
|
18
|
+
|
19
|
+
def query(options={}, &block)
|
20
|
+
q = capture(&block)
|
21
|
+
report = Sequel::Reporter::Report.from_query(@db, q)
|
22
|
+
if options[:pivot]
|
23
|
+
report = report.pivot(options[:pivot], options[:pivot_sort_order])
|
24
|
+
end
|
25
|
+
report
|
26
|
+
end
|
27
|
+
|
28
|
+
def linkify(links, row, value, display_value)
|
29
|
+
links.each do |key, val|
|
30
|
+
if key.is_a? String
|
31
|
+
key = /^#{key}$/
|
32
|
+
end
|
33
|
+
|
34
|
+
if key.match(value[1].title.to_s)
|
35
|
+
url = String.new(links[key])
|
36
|
+
row.each_with_index do |v,i|
|
37
|
+
url.gsub!(":#{i}", CGI.escape(v[0].to_s))
|
38
|
+
end
|
39
|
+
|
40
|
+
url.gsub!(':title', CGI.escape(value[1].title.to_s))
|
41
|
+
url.gsub!(':now', CGI.escape(DateTime.now.strftime('%Y-%m-%d')))
|
42
|
+
display_value = "<a href='#{url}'>#{escape_html(display_value)}</a>"
|
43
|
+
else
|
44
|
+
display_value = escape_html(display_value)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
display_value
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module Sequel::Reporter
|
2
|
+
class Field
|
3
|
+
|
4
|
+
attr_reader :title, :value_type, :span_class
|
5
|
+
|
6
|
+
def initialize(title, value_type, span_class)
|
7
|
+
@title = title
|
8
|
+
@value_type = value_type
|
9
|
+
@span_class = span_class
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
self.title == other.title && \
|
14
|
+
self.value_type == other.value_type && \
|
15
|
+
self.span_class == other.span_class
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class NumberField < Field
|
20
|
+
def initialize(title)
|
21
|
+
super(title, 'number', 'pull-right')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class StringField < Field
|
26
|
+
def initialize(title)
|
27
|
+
super(title, 'string', 'pull-left')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Value
|
32
|
+
def initialize(val)
|
33
|
+
@val = val
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
@val
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class NumericValue < Value
|
42
|
+
def to_s
|
43
|
+
sprintf("%0.2f", @val)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Report
|
48
|
+
|
49
|
+
attr_accessor :error, :fields, :rows
|
50
|
+
|
51
|
+
@@params = {}
|
52
|
+
|
53
|
+
def self.params=(params)
|
54
|
+
@@params = params
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.params
|
58
|
+
@@params
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.from_query(db, query)
|
62
|
+
|
63
|
+
@@params.each do |key, val|
|
64
|
+
params[key.to_sym] = val
|
65
|
+
end
|
66
|
+
|
67
|
+
ds = db.fetch(query, params)
|
68
|
+
report = self.new
|
69
|
+
begin
|
70
|
+
row = ds.first
|
71
|
+
if row.nil?
|
72
|
+
raise "No data"
|
73
|
+
end
|
74
|
+
ds.columns.each do |col|
|
75
|
+
value = row[col]
|
76
|
+
if value.is_a? Numeric
|
77
|
+
report.add_field NumberField.new(col.to_s)
|
78
|
+
else
|
79
|
+
report.add_field StringField.new(col.to_s)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
ds.each do |row|
|
84
|
+
vals = []
|
85
|
+
ds.columns.each do |col|
|
86
|
+
vals << row[col]
|
87
|
+
end
|
88
|
+
report.add_row(vals)
|
89
|
+
end
|
90
|
+
rescue Exception => e
|
91
|
+
report.error = e
|
92
|
+
end
|
93
|
+
|
94
|
+
return report
|
95
|
+
end
|
96
|
+
|
97
|
+
def initialize
|
98
|
+
@fields = []
|
99
|
+
@rows = []
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_field(field)
|
103
|
+
@fields << field
|
104
|
+
end
|
105
|
+
|
106
|
+
def add_row(row)
|
107
|
+
if row.length != @fields.length
|
108
|
+
raise "row length not equal to fields length"
|
109
|
+
end
|
110
|
+
@rows << row
|
111
|
+
end
|
112
|
+
|
113
|
+
def each_row
|
114
|
+
@rows.each do |row|
|
115
|
+
yield row.zip(@fields)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def pivot(column, sort_order)
|
120
|
+
new_report = self.class.new
|
121
|
+
|
122
|
+
bucket_column_index = 0
|
123
|
+
self.fields.each_with_index do |f, i|
|
124
|
+
if f.title == column
|
125
|
+
bucket_column_index = i
|
126
|
+
break
|
127
|
+
else
|
128
|
+
new_report.add_field(f)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
buckets = {}
|
133
|
+
new_rows = {}
|
134
|
+
|
135
|
+
self.each_row do |row|
|
136
|
+
key = row[0, bucket_column_index].map { |r| r[0] }
|
137
|
+
bucket_name = row[bucket_column_index][0]
|
138
|
+
bucket_value = row[bucket_column_index + 1][0]
|
139
|
+
|
140
|
+
if not buckets.has_key? bucket_name
|
141
|
+
field = bucket_value.is_a?(Numeric) ? NumberField.new(bucket_name) : StringField.new(bucket_name)
|
142
|
+
buckets[bucket_name] = field
|
143
|
+
end
|
144
|
+
|
145
|
+
new_rows[key] ||= {}
|
146
|
+
new_rows[key][bucket_name] = bucket_value
|
147
|
+
end
|
148
|
+
|
149
|
+
bucket_keys = buckets.keys.sort
|
150
|
+
if sort_order && sort_order == 'desc'
|
151
|
+
bucket_keys = bucket_keys.reverse
|
152
|
+
end
|
153
|
+
|
154
|
+
bucket_keys.each do |bucket|
|
155
|
+
new_report.add_field(buckets[bucket])
|
156
|
+
end
|
157
|
+
|
158
|
+
new_rows.each do |key, value|
|
159
|
+
row = key
|
160
|
+
bucket_keys.each do |b|
|
161
|
+
row << value[b]
|
162
|
+
end
|
163
|
+
|
164
|
+
new_report.add_row(row)
|
165
|
+
end
|
166
|
+
|
167
|
+
return new_report
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sequel-reporter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "sequel-reporter"
|
8
|
+
gem.version = Sequel::Reporter::VERSION
|
9
|
+
gem.authors = ["Pete Keen"]
|
10
|
+
gem.email = ["peter.keen@bugsplat.info"]
|
11
|
+
gem.description = %q{An opinionated framework for writing reporting applications}
|
12
|
+
gem.summary = %q{An opinionated framework for writing reporting applications}
|
13
|
+
gem.homepage = "https://github.com/peterkeen/sequel-reporter"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency('sqlite3')
|
21
|
+
gem.add_dependency('rspec')
|
22
|
+
gem.add_dependency('sinatra')
|
23
|
+
gem.add_dependency('sinatra-contrib')
|
24
|
+
gem.add_dependency('sequel')
|
25
|
+
end
|
data/test/report_spec.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
|
2
|
+
|
3
|
+
describe Sequel::Reporter::Report do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@things.insert(:id => 1, :something => "hi", :other => "2013-02-18")
|
7
|
+
@things.insert(:id => 2, :something => "ho", :other => "2013-02-19")
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#from_query" do
|
11
|
+
it "should run a query" do
|
12
|
+
report = Sequel::Reporter::Report.from_query(@db, "select count(1) as foo from things")
|
13
|
+
rows = []
|
14
|
+
report.each_row do |row|
|
15
|
+
rows << row
|
16
|
+
end
|
17
|
+
|
18
|
+
rows[0][0][0].should eq(2)
|
19
|
+
rows[0][0][1].should eq(Sequel::Reporter::NumberField.new('foo'))
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should use params" do
|
23
|
+
Sequel::Reporter::Report.params = {:blah => "hi"}
|
24
|
+
report = Sequel::Reporter::Report.from_query(@db, "select count(1) as foo from things where something = :blah")
|
25
|
+
rows = []
|
26
|
+
report.each_row do |row|
|
27
|
+
rows << row
|
28
|
+
end
|
29
|
+
|
30
|
+
rows[0][0][0].should eq(1)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#pivot" do
|
35
|
+
|
36
|
+
before :each do
|
37
|
+
@things.insert(:id => 1, :something => "hi", :other => "2013-02-18")
|
38
|
+
@things.insert(:id => 2, :something => "ho", :other => "2013-02-19")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should create the correct fields" do
|
42
|
+
report = Sequel::Reporter::Report.from_query(@db, "select other, something, count(1) from things group by other, something")
|
43
|
+
report = report.pivot("something", "asc")
|
44
|
+
|
45
|
+
report.fields.should eq([
|
46
|
+
Sequel::Reporter::StringField.new('other'),
|
47
|
+
Sequel::Reporter::NumberField.new('hi'),
|
48
|
+
Sequel::Reporter::NumberField.new('ho'),
|
49
|
+
])
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should put the values in the right place" do
|
53
|
+
report = Sequel::Reporter::Report.from_query(@db, "select other, something, count(1) from things group by other, something")
|
54
|
+
report = report.pivot("something", "asc")
|
55
|
+
|
56
|
+
report.rows.should eq([
|
57
|
+
[Date.new(2013,2,18), 2, nil],
|
58
|
+
[Date.new(2013,2,19), nil, 2]
|
59
|
+
])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/test/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'sequel-reporter/application'
|
5
|
+
require 'sequel-reporter/report'
|
6
|
+
require 'sequel-reporter/helpers'
|
7
|
+
require 'sequel'
|
8
|
+
require 'sqlite3'
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.before(:each) do
|
12
|
+
@db = Sequel.sqlite
|
13
|
+
@db.run("create table things (id integer, something text, other date)")
|
14
|
+
@things = @db[:things]
|
15
|
+
end
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sequel-reporter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pete Keen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sqlite3
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: sinatra
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sinatra-contrib
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: sequel
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: An opinionated framework for writing reporting applications
|
95
|
+
email:
|
96
|
+
- peter.keen@bugsplat.info
|
97
|
+
executables:
|
98
|
+
- sequel-reporter
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- bin/sequel-reporter
|
108
|
+
- data/Gemfile
|
109
|
+
- data/Rakefile.tt
|
110
|
+
- data/application.rb.tt
|
111
|
+
- data/config.ru
|
112
|
+
- data/lib/.gitkeep
|
113
|
+
- data/migrate/.gitkeep
|
114
|
+
- data/public/.gitkeep
|
115
|
+
- data/public/css/bootstrap.css
|
116
|
+
- data/public/css/bootstrap.min.css
|
117
|
+
- data/public/img/glyphicons-halflings-white.png
|
118
|
+
- data/public/img/glyphicons-halflings.png
|
119
|
+
- data/public/js/bootstrap.js
|
120
|
+
- data/public/js/bootstrap.min.js
|
121
|
+
- data/public/js/jquery-1.9.1.js
|
122
|
+
- data/views/error.erb
|
123
|
+
- data/views/layout.erb
|
124
|
+
- data/views/reports/dashboard.erb
|
125
|
+
- data/views/table.erb
|
126
|
+
- lib/sequel-reporter.rb
|
127
|
+
- lib/sequel-reporter/application.rb
|
128
|
+
- lib/sequel-reporter/cli.rb
|
129
|
+
- lib/sequel-reporter/helpers.rb
|
130
|
+
- lib/sequel-reporter/report.rb
|
131
|
+
- lib/sequel-reporter/version.rb
|
132
|
+
- sequel-reporter.gemspec
|
133
|
+
- test/report_spec.rb
|
134
|
+
- test/spec_helper.rb
|
135
|
+
homepage: https://github.com/peterkeen/sequel-reporter
|
136
|
+
licenses: []
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ! '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 1.8.23
|
156
|
+
signing_key:
|
157
|
+
specification_version: 3
|
158
|
+
summary: An opinionated framework for writing reporting applications
|
159
|
+
test_files:
|
160
|
+
- test/report_spec.rb
|
161
|
+
- test/spec_helper.rb
|