Dex_Rack 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+
6
+ coverage
7
+ rdoc
8
+ .yardoc
data/Dex_Rack.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ $:.push File.expand_path("../lib", __FILE__)
4
+ require "Dex_Rack/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "Dex_Rack"
8
+ s.version = Dex_Rack::VERSION
9
+ s.authors = ["da99"]
10
+ s.email = ["i-hate-spam-45671204@mailinator.com"]
11
+ s.homepage = "https://github.com/da99/Dex_Rack"
12
+ s.summary = %q{A Rack app to display Dex exceptions.}
13
+ s.description = %q{
14
+ It is a web-frontend for Dex.
15
+ Update and view exceptions logged with the Dex gem.
16
+ }
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_development_dependency 'bacon'
24
+ s.add_development_dependency 'rake'
25
+ s.add_development_dependency 'Bacon_Colored'
26
+ s.add_development_dependency 'pry'
27
+ s.add_development_dependency 'rack-test'
28
+
29
+ # Specify any dependencies here; for example:
30
+ s.add_runtime_dependency 'sinatra'
31
+ s.add_runtime_dependency 'markaby'
32
+ s.add_runtime_dependency 'thin'
33
+ s.add_runtime_dependency 'sinatra-reloader'
34
+ s.add_runtime_dependency 'chronic_duration'
35
+ s.add_runtime_dependency 'Dex'
36
+ end
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ source "http://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in Bob.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+
2
+ Dex\_Rack
3
+ ================
4
+
5
+ A Ruby gem.
6
+
7
+ Installation
8
+ ------------
9
+
10
+ gem install Dex_Rack
11
+
12
+ Usage
13
+ ------
14
+
15
+ Create a `config.ru` file:
16
+
17
+ require "Dex_Rack"
18
+
19
+ Dex_Rack.set :dex, ( Dex.db("My.SQLITE.file.db") && Dex )
20
+ run Dex_Rack
21
+
22
+ In your shell:
23
+
24
+ rackup -p 3000
25
+
26
+ Visit: [http://localhost:3000](http://localhost:3000)
27
+
28
+ Run Tests
29
+ ---------
30
+
31
+ git clone git@github.com:da99/Dex_Rack.git
32
+ cd Dex_Rack
33
+ bundle update
34
+ bundle exec bacon spec/lib/main.rb
35
+
36
+
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/gem_tasks"
data/lib/Dex_Rack.rb ADDED
@@ -0,0 +1,194 @@
1
+ require 'Dex_Rack/version'
2
+ require 'Dex'
3
+ require 'markaby'
4
+ require 'chronic_duration'
5
+ require 'cgi'
6
+
7
+ class Dex_Rack
8
+
9
+ RACK_DIR = File.join( File.dirname( __FILE__ ) , "/Dex_Rack" )
10
+
11
+ set :dex, ( Dex.db("/tmp/dex.rack.sample.db") && Dex )
12
+
13
+ use Rack::Lint
14
+
15
+ set :public_folder, RACK_DIR + "/public"
16
+ set :views_folder, RACK_DIR + "/views"
17
+
18
+ # use Rack::Static, \
19
+ # :urls=>%w{ /stylesheets/ /javascripts/ /images/ /index.html }, \
20
+ # :root=> RACK_DIR
21
+
22
+ configure :development do
23
+ require 'sinatra/reloader'
24
+ register Sinatra::Reloader
25
+ use Rack::CommonLogger
26
+ end
27
+
28
+ get "/" do
29
+ recent
30
+ end
31
+
32
+ get "/recent/:page" do | page |
33
+ recent page
34
+ end
35
+
36
+ get %r!\A/(\d+)\Z! do | id |
37
+ r = dex.filter(:id=>id).first
38
+
39
+ if r
40
+ vars= Hash[
41
+ :title=>"#{r[:exception]}: #{r[:message]}",
42
+ :record=>r,
43
+ :table_keys=>(r.keys - [:exception, :message, :backtrace, :status]),
44
+ :app=>self
45
+ ]
46
+
47
+ s = self
48
+ status = status_to_word(r[:status])
49
+ vars[:status_class] = status.downcase
50
+ vars[:status_word] = status
51
+ r[:human_time] = human_time(r[:created_at])
52
+ r[:backtrace] = backtrace_to_html(r[:backtrace])
53
+ vars[:table_keys] << :human_time
54
+ layout vars, :record
55
+ else
56
+ status 404
57
+ layout Hash[:id=>id, :title=>"Not Found: Record ##{id}"], :record_404
58
+ end
59
+
60
+ end
61
+
62
+ get "/:id/toggle" do |id|
63
+ r = dex.filter(:id=>id).first
64
+ s = r[:status] == 0 ? 1 : 0
65
+ dex.filter(:id=>id).update(:status=>s)
66
+ redirect to("/#{r[:id]}"), 302
67
+ end
68
+
69
+ delete "/:id" do | id |
70
+ dex.filter(:id=>id).delete
71
+ redirect to('/'), 303
72
+ end
73
+
74
+ get "/create-sample" do
75
+ begin
76
+ raise ArgumentError, request.path_info
77
+ rescue ArgumentError => e
78
+ dex.insert e
79
+ end
80
+ redirect to("/"), 302
81
+ end
82
+
83
+ %w{ dex dex? }.each { |m|
84
+ eval %~
85
+ def #{m} *args
86
+ settings.#{m}(*args)
87
+ end
88
+ ~
89
+ }
90
+
91
+ def recent page = :last, limit = 10
92
+ nav = page_nav( dex.count, limit, page)
93
+
94
+ return redirect(to('/'), 302) if !nav
95
+
96
+ nav[:prev_url] = "/recent/#{nav[:prev]}" if nav[:prev]
97
+ nav[:next_url] = "/recent/#{nav[:next]}" if nav[:next]
98
+ nav[:next_url] = "/" if nav[:next] == nav[:total]
99
+
100
+ vars = nav.merge(
101
+ Hash[
102
+ :title => "Dex List",
103
+ :list => dex.limit(nav[:limit], nav[:offset]).to_a.reverse,
104
+ :app => self
105
+ ])
106
+
107
+ layout(vars, :index)
108
+ end
109
+
110
+ def layout vars, file_name
111
+ Markaby::Builder.set(:indent, 2)
112
+ mab = Markaby::Builder.new
113
+ file = File.join(settings.views_folder, "/layout.rb")
114
+ vars[:view_file] = File.join(settings.views_folder, "#{file_name}.rb" )
115
+ vars[:app] = self
116
+ mab.instance_eval {
117
+ eval File.read(file), nil, file, 1
118
+ }
119
+ mab.to_s
120
+ end
121
+
122
+ def status_to_word num
123
+ case num
124
+ when 0
125
+ "Unresolved"
126
+ when 1
127
+ "Resolved"
128
+ end
129
+ end
130
+
131
+ def backtrace_to_html s
132
+ last_file = nil
133
+ str = ""
134
+ s.split("\n").map { |l|
135
+ file, num, code = l.split(':')
136
+ str.<< %!
137
+ <div class="line">
138
+ <span class="num">#{CGI::escapeHTML num}</span>
139
+ <span class="code">#{CGI::escapeHTML code}</span>
140
+ </div>!
141
+ str.<< %!
142
+ <div class="file">#{CGI::escapeHTML file}</div>
143
+ ! if file != last_file
144
+
145
+ last_file = file
146
+ str
147
+ }.join
148
+ end
149
+
150
+ def human_time t
151
+ target = Time.now.utc.to_i - t.to_i
152
+ if target < 61
153
+ return "<1m ago"
154
+ else
155
+ ChronicDuration.output(target, :format=>:short).sub(/\d+s\Z/, '') + " ago"
156
+ end
157
+ end
158
+
159
+ def page_nav count, div, page = :last
160
+ count = count.to_i
161
+
162
+ div = div.to_i
163
+ total = ( count / Float(div) ).ceil
164
+ page = total if page == :last
165
+ page = page.to_i
166
+
167
+ if count > 0
168
+ if total < 1 || page < 1 || page > total || div < 2
169
+ return nil
170
+ end
171
+ end
172
+
173
+ n = page + 1
174
+ n = nil if n > total
175
+ p = page - 1
176
+ p = nil if p < 1
177
+ offset = div * (page - 1)
178
+ offset = 0 if offset < 1
179
+
180
+ Hash[
181
+
182
+ :total => total,
183
+ :next => n,
184
+ :prev => p,
185
+ :page => page,
186
+
187
+ :count => count,
188
+ :limit => div,
189
+ :offset => offset
190
+
191
+ ]
192
+ end
193
+
194
+ end # === class Dex_Rack
@@ -0,0 +1,4 @@
1
+
2
+ require "Dex_Rack"
3
+
4
+ run Dex_Rack
Binary file
@@ -0,0 +1,16 @@
1
+ $(document).ready(function() {
2
+
3
+ $("#show_backtrace").click(function() {
4
+ $("#show_backtrace").css("visibility", "hidden");
5
+ $("#hide_backtrace").css("visibility", "visible");
6
+ $("#backtrace").show();
7
+ });
8
+
9
+ $("#hide_backtrace").click(function() {
10
+ $("#show_backtrace").css("visibility", "visible");
11
+ $("#hide_backtrace").css("visibility", "hidden");
12
+ $("#backtrace").hide();
13
+ });
14
+
15
+ });
16
+
@@ -0,0 +1,29 @@
1
+
2
+ /**
3
+ * Skeleton V1.1
4
+ * Copyright 2011, Dave Gamache
5
+ * www.getskeleton.com
6
+ * Free to use under the MIT license.
7
+ * http://www.opensource.org/licenses/mit-license.php
8
+ * 8/17/2011
9
+ */
10
+
11
+ (function ($) {
12
+ // hash change handler
13
+ function hashchange () {
14
+ var hash = window.location.hash
15
+ , el = $('ul.tabs [href*="' + hash + '"]')
16
+ , content = $(hash)
17
+
18
+ if (el.length && !el.hasClass('active') && content.length) {
19
+ el.closest('.tabs').find('.active').removeClass('active');
20
+ el.addClass('active');
21
+ content.show().addClass('active').siblings().hide().removeClass('active');
22
+ }
23
+ }
24
+
25
+ // listen on event and fire right away
26
+ $(window).on('hashchange.skeleton', hashchange);
27
+ hashchange();
28
+ $(hashchange);
29
+ })(jQuery);
@@ -0,0 +1,5 @@
1
+ # www.robotstxt.org/
2
+ # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449
3
+
4
+ User-agent: *
5
+
@@ -0,0 +1,207 @@
1
+ /* From: http://css-tricks.com/perfect-full-page-background-image/ */
2
+ body {
3
+ background: url("/images/texture/straw-flowers.gif") repeat-x 0 29px #FCFBF0;
4
+ background: #FCFBF0;
5
+ background: #FAFAFA;
6
+ font-family: 'Oxygen', sans-serif;
7
+ padding: 0 40px 40px 40px;
8
+ }
9
+
10
+ div.container {
11
+ background: white;
12
+ -moz-border-radius: 0 0 10px 10px;
13
+ border-radius: 0 0 10px 10px;
14
+ }
15
+
16
+ #header, #footer {
17
+ background: url('/images/texture/9.jpg') grey;
18
+ padding: 5px 10px 10px 20px ;
19
+ }
20
+
21
+ #header, h1, h2, h3 {
22
+ font-family: 'Bree Serif', serif;
23
+ }
24
+
25
+ #footer {
26
+ color: lightgrey;
27
+ font-size: 80%;
28
+ -moz-border-radius: 0 0 10px 10px;
29
+ border-radius: 0 0 10px 10px;
30
+ min-height: 30px;
31
+ }
32
+
33
+ #header h1 {
34
+ font-size: 200%;
35
+ color: white;
36
+ }
37
+
38
+ body.unresolved #header h1 {
39
+ color: pink;
40
+ }
41
+
42
+ body.unresolved #header h1 span.message {
43
+ color: white;
44
+ }
45
+
46
+ body.resolved #header h1 {
47
+ color: white;
48
+ }
49
+
50
+ #nav {
51
+ padding: 0 20px;
52
+ font-size: small;
53
+ background: white;
54
+ }
55
+
56
+ #content {
57
+ padding: 10px 20px 20px 20px;
58
+ background: white;
59
+ }
60
+
61
+ a#hide_backtrace {
62
+ visibility: hidden;
63
+ }
64
+
65
+ div.line:hover, div.file:hover {
66
+ background: lightyellow;
67
+ }
68
+
69
+ #more_info div.key {
70
+ font-weight: bold;
71
+ text-align: right;
72
+ display: inline-block;
73
+ min-width: 200px;
74
+ }
75
+
76
+ #more_info div.val {
77
+ display: inline-block;
78
+ }
79
+
80
+
81
+ table {
82
+ margin: 10px 10px 10px 0;
83
+ }
84
+
85
+ table tr:first-child td:first-child {
86
+ -moz-border-radius: 5px 0 0 0;
87
+ border-radius: 5px 0 0 0;
88
+ }
89
+
90
+ table tr:first-child td:last-child {
91
+ -moz-border-radius: 0 5px 0 0;
92
+ border-radius: 0 5px 0 0;
93
+ }
94
+
95
+ table tr:last-child td:first-child {
96
+ -moz-border-radius: 0 0 0 5px;
97
+ border-radius: 0 0 0 5px;
98
+ }
99
+
100
+ table tr:last-child td:last-child {
101
+ -moz-border-radius: 0 0 5px 0;
102
+ border-radius: 0 0 5px 0;
103
+ }
104
+
105
+ td {
106
+ background: lightgrey;
107
+ padding: 8px;
108
+ }
109
+
110
+ td.key {
111
+ text-align: right;
112
+ font-weight: bold;
113
+ padding: 8px 10px 8px 10px;
114
+ }
115
+
116
+ td.val {
117
+ background: #FFFFE6;
118
+ }
119
+
120
+ span.exception {
121
+ font-weight: bold;
122
+ }
123
+
124
+
125
+ span.status, a.button, a:link {
126
+ display: inline-block;
127
+ padding: 5px 8px;
128
+ font-size: 8pt;
129
+ font-weight: bold;
130
+ text-transform: uppercase;
131
+ text-align: center;
132
+ -moz-border-radius: 5px;
133
+ border-radius: 5px;
134
+ color: white;
135
+ }
136
+
137
+ a:link {
138
+ color: #8C728A;
139
+ text-shadow: none;
140
+ }
141
+
142
+ a:visited {
143
+ color: #B87FB3;
144
+ }
145
+
146
+ a:hover {
147
+ color: pink;
148
+ background: grey;
149
+ }
150
+
151
+ span.status {
152
+ background: grey;
153
+ }
154
+
155
+ a.button:link {
156
+ background: lightgrey;
157
+ color: #B87FB3;
158
+ }
159
+
160
+ a.button:visited {
161
+ color: grey;
162
+ }
163
+
164
+ a.button:hover, a.button:active {
165
+ color: pink;
166
+ background: grey;
167
+ }
168
+
169
+ div.unresolved h1, span.unresolved {
170
+ color: pink;
171
+ }
172
+
173
+ div.resolved h1, span.resolved {
174
+ color: white;
175
+ }
176
+
177
+ span.num {
178
+ font-weight: bold;
179
+ }
180
+
181
+ div.line {
182
+ padding: 5px;
183
+ }
184
+
185
+ div.file {
186
+ margin: 0 0 10px 0;
187
+ font-weight: bold;
188
+ padding: 5px;
189
+ }
190
+
191
+
192
+ div.record_in_list {
193
+ padding: 2px 0;
194
+ }
195
+
196
+ #toggle_backtrace {
197
+ display: none;
198
+ }
199
+
200
+ h3 {
201
+ font-size: 150%;
202
+ margin-bottom: 10px;
203
+ }
204
+ #backtrace {
205
+ padding-left: 20px;
206
+ }
207
+
@@ -0,0 +1,48 @@
1
+ /* http://meyerweb.com/eric/tools/css/reset/
2
+ v2.0 | 20110126
3
+ License: none (public domain)
4
+ */
5
+
6
+ html, body, div, span, applet, object, iframe,
7
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8
+ a, abbr, acronym, address, big, cite, code,
9
+ del, dfn, em, img, ins, kbd, q, s, samp,
10
+ small, strike, strong, sub, sup, tt, var,
11
+ b, u, i, center,
12
+ dl, dt, dd, ol, ul, li,
13
+ fieldset, form, label, legend,
14
+ table, caption, tbody, tfoot, thead, tr, th, td,
15
+ article, aside, canvas, details, embed,
16
+ figure, figcaption, footer, header, hgroup,
17
+ menu, nav, output, ruby, section, summary,
18
+ time, mark, audio, video {
19
+ margin: 0;
20
+ padding: 0;
21
+ border: 0;
22
+ font-size: 100%;
23
+ font: inherit;
24
+ vertical-align: baseline;
25
+ }
26
+ /* HTML5 display-role reset for older browsers */
27
+ article, aside, details, figcaption, figure,
28
+ footer, header, hgroup, menu, nav, section {
29
+ display: block;
30
+ }
31
+ body {
32
+ line-height: 1;
33
+ }
34
+ ol, ul {
35
+ list-style: none;
36
+ }
37
+ blockquote, q {
38
+ quotes: none;
39
+ }
40
+ blockquote:before, blockquote:after,
41
+ q:before, q:after {
42
+ content: '';
43
+ content: none;
44
+ }
45
+ table {
46
+ border-collapse: collapse;
47
+ border-spacing: 0;
48
+ }
@@ -0,0 +1,5 @@
1
+ require "sinatra/base"
2
+
3
+ class Dex_Rack < Sinatra::Base
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,68 @@
1
+ div.header! {
2
+ h1 {
3
+ span.exception vars[:title]
4
+ span.message vars[:message]
5
+ }
6
+ }
7
+
8
+ if vars[:app].request.path_info != '/'
9
+ div.nav! {
10
+ a(:href=>'/') { "Home"}
11
+ span.towards ">>"
12
+ span.location vars[:title]
13
+ }
14
+ end
15
+
16
+ div.content! {
17
+
18
+ if vars[:app].request.path_info == '/'
19
+ table {
20
+ tr {
21
+ td.key "Database:"
22
+ td.val vars[:app].dex.db_name.to_s
23
+ }
24
+ tr {
25
+ td.key "Table:"
26
+ td.val vars[:app].dex.table_name.to_s
27
+ }
28
+ }
29
+ end
30
+
31
+ div.recent_nav! {
32
+
33
+ if vars[:prev_url]
34
+ a(:href=>vars[:prev_url]) { "<< Back in Time" }
35
+ end
36
+
37
+ if vars[:next_url]
38
+ a(:href=>vars[:next_url]) { "Forward In Time >>" }
39
+ end
40
+
41
+ }
42
+
43
+ if vars[:list].empty?
44
+ div.empty {
45
+ p "No exceptions created."
46
+ a.button( :href=>"/create-sample" ) {
47
+ "Create Sample Exception"
48
+ }
49
+ }
50
+
51
+ else
52
+
53
+ vars[:list].each { |db|
54
+ div.record_in_list {
55
+ p {
56
+ a.button(:href=>"/#{db[:id]}") {
57
+ "View"
58
+ }
59
+ span.time( vars[:app].human_time(db[:created_at]) )
60
+ span.status.send(vars[:app].status_to_word(db[:status]).downcase, vars[:app].status_to_word(db[:status]))
61
+ span.exception "#{db[:exception]}:"
62
+ span.message db[:message]
63
+ }
64
+ }
65
+ }
66
+
67
+ end
68
+ }
@@ -0,0 +1,36 @@
1
+ xhtml_strict do
2
+
3
+ head {
4
+
5
+ link( :href=>'http://fonts.googleapis.com/css?family=Bree+Serif|Oxygen', :rel=>'stylesheet', :type=>'text/css' )
6
+
7
+ title vars[:title]
8
+ %w{ reset dex }.each { |name|
9
+ link(:rel=>"stylesheet", :href=>"/stylesheets/#{name}.css")
10
+ }
11
+ script(
12
+ :type=>"text/javascript",
13
+ :src=>"http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"
14
+ ) {}
15
+ script(
16
+ :type=>"text/javascript",
17
+ :src=>"/javascripts/dex.js"
18
+ ) {}
19
+ }
20
+
21
+ body(:class=>[vars[:status_class]].compact.join(' ')) {
22
+
23
+ eval File.read(vars[:view_file]), nil, vars[:view_file], 1
24
+
25
+
26
+ div.footer! {
27
+ if vars[:app].request.path_info == '/'
28
+ %~
29
+ <span>Background from: </span>
30
+ <a href="http://www.backgroundlabs.com" title="Background Labs"><img src="http://www.backgroundlabs.com/images/backgroundlabs88x15.gif" border="0" alt="Background Labs"/></a>
31
+ ~
32
+ end
33
+ }
34
+ }
35
+ end
36
+
@@ -0,0 +1,51 @@
1
+
2
+
3
+
4
+ div.header! {
5
+ h1 {
6
+ span.exception "#{vars[:record][:exception]}:"
7
+ span.message vars[:record][:message]
8
+ }
9
+ }
10
+
11
+ if vars[:app].request.path_info != '/'
12
+ div.nav! {
13
+ a(:href=>'/') { "Home"}
14
+ span.towards ">>"
15
+ span.location vars[:title]
16
+ }
17
+ end
18
+
19
+ div.content! {
20
+ div {
21
+ span.status.send vars[:status_class].downcase, vars[:status_word]
22
+ a.button(:href=>"/#{vars[:record][:id]}/toggle") { "Toggle" }
23
+ }
24
+
25
+ unless vars[:table_keys].empty?
26
+ table {
27
+ vars[:table_keys].each { |k|
28
+ tr {
29
+ td.key k.inspect
30
+ td.val vars[:record][k]
31
+ }
32
+ }
33
+ }
34
+ end
35
+
36
+ div.toggle_backtrace! {
37
+ div {
38
+ a.button.show_backtrace!(:href=>"#show") { "Show Backtrace" }
39
+ }
40
+ div.omega {
41
+ a.button.hide_backtrace!(:href=>"#hide") { "Hide Backtrace" }
42
+ }
43
+ }
44
+
45
+ h3 "Backtrace:"
46
+ div.backtrace! {
47
+ vars[:record][:backtrace]
48
+ }
49
+
50
+
51
+ }
@@ -0,0 +1,3 @@
1
+ div.sixteen.columns {
2
+ h2 vars[:title]
3
+ }
data/spec/Dex_App.rb ADDED
@@ -0,0 +1,88 @@
1
+
2
+ describe "get /" do
3
+
4
+ behaves_like 'Test DB'
5
+
6
+ it "renders message when there are no exceptions" do
7
+ get "/"
8
+ should_render %!No exceptions!
9
+ end
10
+
11
+ it "renders a recent list of 10" do
12
+ 5.times { |i| Dex.insert except("Err: #{i}") }
13
+
14
+ get "/"
15
+ 5.times { |i|
16
+ last_response.body.should.match %r!Err: #{i}!
17
+ }
18
+ end
19
+
20
+ end # === get /
21
+
22
+ describe "get /recent/:num" do
23
+
24
+ behaves_like 'Test DB'
25
+
26
+ it "/recent/:num renders a list" do
27
+ n = rand(10) + 1
28
+ n.times { |i| Dex.insert except("N: #{i}") }
29
+
30
+ get "/recent/#{1}"
31
+ n.times { |i|
32
+ last_response.body.should.match %r!N: #{i}!
33
+ }
34
+ end
35
+
36
+ end # === get /recent/num
37
+
38
+ describe "get /:id" do
39
+
40
+ behaves_like 'Test DB'
41
+
42
+ it "displays record" do
43
+ id = Dex.insert(except "rand err")
44
+ get "/#{id}"
45
+ should_render "rand err"
46
+ end
47
+
48
+ end # === get /:id
49
+
50
+ describe "get /:id/toggle" do
51
+
52
+ behaves_like 'Test DB'
53
+
54
+ it "updates status of record" do
55
+ id = Dex.insert(except "rand err")
56
+ get "/#{id}/toggle"
57
+ Dex.filter(:id=>id).first[:status]
58
+ .should == 1
59
+ end
60
+
61
+ it "redirects to /:id 302" do
62
+ id = Dex.insert(except "rand err")
63
+ get "/#{id}/toggle"
64
+ should_redirect_to "/#{id}", 302
65
+ end
66
+
67
+ end # === put /:id/status
68
+
69
+ describe "delete /:id" do
70
+
71
+ behaves_like 'Test DB'
72
+
73
+ it "deletes record" do
74
+ Dex.insert(except("Deleted"))
75
+ r = Dex.recent(1)
76
+ delete "/#{r[:id]}"
77
+ Dex.count.should == 0
78
+ end
79
+
80
+ it "redirects to / 303" do
81
+ Dex.insert(except("Deleted"))
82
+ r = Dex.recent(1)
83
+ delete "/#{r[:id]}"
84
+ should_redirect_to "/"
85
+ end
86
+
87
+ end # === delete /:id
88
+
data/spec/bin.rb ADDED
@@ -0,0 +1,13 @@
1
+
2
+ bins = Dir.glob("bin/*")
3
+
4
+ unless bins.empty?
5
+ describe "permissions of bin/" do
6
+ bins.each { |file|
7
+ it "should chmod 755 for: #{file}" do
8
+ `stat -c %a #{file}`.strip
9
+ .should.be == "755"
10
+ end
11
+ }
12
+ end # === permissions of bin/
13
+ end # === unless bins.empty?
data/spec/lib/main.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.print e.message, "\n"
7
+ $stderr.print "Run `bundle install` to install missing gems\n"
8
+ exit e.status_code
9
+ end
10
+ require 'bacon'
11
+
12
+ Gem_Dir = File.expand_path( File.join(File.dirname(__FILE__) + '/../..') )
13
+ $LOAD_PATH.unshift Gem_Dir
14
+ $LOAD_PATH.unshift( Gem_Dir + "/lib" )
15
+
16
+ Bacon.summary_on_exit
17
+
18
+ require 'Bacon_Colored'
19
+ require 'pry'
20
+ require 'rack/test'
21
+ require 'Dex_Rack'
22
+
23
+ Dex_Rack.set :environment, :test
24
+ Dex_Rack.set :dex, ( Dex.db(":memory:") && Dex )
25
+
26
+ def except e
27
+ begin
28
+ raise e
29
+ rescue Object => e
30
+ $!
31
+ end
32
+ end
33
+
34
+ shared "Test DB" do
35
+ before {
36
+ Dex.table.delete
37
+ }
38
+ end
39
+
40
+ class Bacon::Context
41
+ include Rack::Test::Methods
42
+
43
+ def app
44
+ Dex_Rack
45
+ end
46
+
47
+ def should_render txt
48
+ last_response.should.be.ok
49
+ r = txt.respond_to?(:~) ? txt : %r!#{txt}!
50
+ last_response.body.should.match r
51
+ end
52
+
53
+ def should_redirect_to url, status = 303
54
+ last_response.status.should == status
55
+ last_response['Location'].sub( %r!http://(www.)?example.(com|org)!, '' )
56
+ .should == url
57
+ end
58
+
59
+ end # === class Bacon::Context
60
+
61
+
62
+ # ======== Include the tests.
63
+ target_files = ARGV[1, ARGV.size - 1].select { |a| File.file?(a) }
64
+
65
+ if target_files.empty?
66
+
67
+ # include all files
68
+ Dir.glob('./spec/*.rb').each { |file|
69
+ require file.sub('.rb', '') if File.file?(file)
70
+ }
71
+
72
+ else
73
+ # Do nothing. Bacon grabs the file.
74
+
75
+ end
metadata ADDED
@@ -0,0 +1,244 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: Dex_Rack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - da99
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bacon
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
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: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
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: Bacon_Colored
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
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: pry
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
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: rack-test
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
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
+ - !ruby/object:Gem::Dependency
95
+ name: sinatra
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: markaby
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: thin
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: sinatra-reloader
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :runtime
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: chronic_duration
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :runtime
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ - !ruby/object:Gem::Dependency
175
+ name: Dex
176
+ requirement: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ type: :runtime
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ! '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ description: ! "\nIt is a web-frontend for Dex. \nUpdate and view exceptions logged
191
+ with the Dex gem.\n "
192
+ email:
193
+ - i-hate-spam-45671204@mailinator.com
194
+ executables: []
195
+ extensions: []
196
+ extra_rdoc_files: []
197
+ files:
198
+ - .gitignore
199
+ - Dex_Rack.gemspec
200
+ - Gemfile
201
+ - README.md
202
+ - Rakefile
203
+ - lib/Dex_Rack.rb
204
+ - lib/Dex_Rack/config.ru
205
+ - lib/Dex_Rack/public/favicon.ico
206
+ - lib/Dex_Rack/public/images/texture/9.jpg
207
+ - lib/Dex_Rack/public/javascripts/dex.js
208
+ - lib/Dex_Rack/public/javascripts/tabs.js
209
+ - lib/Dex_Rack/public/robots.txt
210
+ - lib/Dex_Rack/public/stylesheets/dex.css
211
+ - lib/Dex_Rack/public/stylesheets/reset.css
212
+ - lib/Dex_Rack/version.rb
213
+ - lib/Dex_Rack/views/index.rb
214
+ - lib/Dex_Rack/views/layout.rb
215
+ - lib/Dex_Rack/views/record.rb
216
+ - lib/Dex_Rack/views/record_404.rb
217
+ - spec/Dex_App.rb
218
+ - spec/bin.rb
219
+ - spec/lib/main.rb
220
+ homepage: https://github.com/da99/Dex_Rack
221
+ licenses: []
222
+ post_install_message:
223
+ rdoc_options: []
224
+ require_paths:
225
+ - lib
226
+ required_ruby_version: !ruby/object:Gem::Requirement
227
+ none: false
228
+ requirements:
229
+ - - ! '>='
230
+ - !ruby/object:Gem::Version
231
+ version: '0'
232
+ required_rubygems_version: !ruby/object:Gem::Requirement
233
+ none: false
234
+ requirements:
235
+ - - ! '>='
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ requirements: []
239
+ rubyforge_project:
240
+ rubygems_version: 1.8.23
241
+ signing_key:
242
+ specification_version: 3
243
+ summary: A Rack app to display Dex exceptions.
244
+ test_files: []