sequel-reporter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|