peek 0.0.5

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 ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # 0.0.1
2
+
3
+ - Initial release.
4
+
5
+ # 0.0.2
6
+
7
+ - Add own tipsy plugin to allow for tooltips.
8
+
9
+ # 0.0.3
10
+
11
+ - Change the scope of the .tipsy selector as it's inserted outside of the Glimpse div.
12
+
13
+ # 0.0.4
14
+
15
+ - Don't capture ` being pressed when in combination with `cmd`
16
+ - Support for [Turbolinks](https://github.com/rails/turbolinks) (#14)
17
+
18
+ # 0.0.5
19
+
20
+ - Namespace the tooltips to the `.glimpse-tooltip` class name to not conflict with any application styles for `.tooltip`. (#18)
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in peek.gemspec
4
+ gemspec
5
+
6
+ gem 'rake'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Garrett Bjerkhoel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,193 @@
1
+ # Peek
2
+
3
+ [![Build Status](https://travis-ci.org/peek/peek.png?branch=master)](https://travis-ci.org/peek/peek)
4
+
5
+ Take a peek into your Rails application.
6
+
7
+ ![Preview](https://f.cloud.github.com/assets/79995/244991/03cee1fa-8a74-11e2-8e33-283cf1298a60.png)
8
+
9
+ This was originally built at GitHub to help us get insight into what's going
10
+ on, this is just an extraction so other Rails applications can have the same.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'peek'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install peek
25
+
26
+ ## Usage
27
+
28
+ To pick which views you want to see in your Peek bar, just create a file at
29
+ `config/initializers/peek.rb` that has a list of the views you'd like to see:
30
+
31
+ ```ruby
32
+ Peek.into Peek::Views::Git, :nwo => 'github/janky'
33
+ Peek.into Peek::Views::Mysql2
34
+ Peek.into Peek::Views::Redis
35
+ Peek.into Peek::Views::Dalli
36
+ ```
37
+
38
+ Feel free to pick and choose from the list or create your own. The order they
39
+ are added to Peek, the order they will appear in your bar.
40
+
41
+ Next, to render the Peek bar in your application just add the following snippet
42
+ just after the opening `<body>` tag in your application layout.
43
+
44
+ ```erb
45
+ <%= render 'peek/bar' %>
46
+ ```
47
+
48
+ It will look like:
49
+
50
+ ```erb
51
+ <html>
52
+ <head>
53
+ <title>Application</title>
54
+ </head>
55
+ <body>
56
+ <%= render 'peek/bar' %>
57
+ <%= yield %>
58
+ </body>
59
+ </html>
60
+ ```
61
+
62
+ Some Peek views require the view to render before data is collected and can
63
+ be presented, ie: the number of MySQL queries ran on the page and how
64
+ long it took.
65
+
66
+ For this to work, you need to include the `peek/results` partial at the end of your
67
+ application layout.
68
+
69
+ It will look like:
70
+
71
+ ```erb
72
+ <html>
73
+ <head>
74
+ <title>Application</title>
75
+ </head>
76
+ <body>
77
+ <%= render 'peek/bar' %>
78
+ <%= yield %>
79
+ <%= render 'peek/results' %>
80
+ </body>
81
+ </html>
82
+ ```
83
+
84
+ Now that you have the partials in your application, you will need to include the
85
+ CSS and JS that help make Peek :sparkles:
86
+
87
+ In `app/assets/stylesheets/application.scss`:
88
+
89
+ ```scss
90
+ //= require peek
91
+ ```
92
+
93
+ In `app/assets/javascripts/application.coffee`:
94
+
95
+ ```coffeescript
96
+ #= require jquery
97
+ #= require jquery_ujs
98
+ #= require peek
99
+ ```
100
+
101
+ Note: Each additional view my have their own CSS and JS you need to require
102
+ which should be stated in their usage documentation.
103
+
104
+ ## Using Peek with PJAX
105
+
106
+ When using [PJAX](https://github.com/defunkt/jquery-pjax) in your application, by default requests won't render the
107
+ application layout which ends up not including the required results partial.
108
+ It's fairly simple to get this working with PJAX if you're using the
109
+ [pjax_rails](https://github.com/rails/pjax_rails) gem.
110
+
111
+ Create a new layout at `app/views/layouts/peek.html.erb`:
112
+
113
+ ```erb
114
+ <%= yield %>
115
+ <%= render 'peek/results' %>
116
+ ```
117
+
118
+ Now you'll just need use the PJAX layout:
119
+
120
+ ```ruby
121
+ class ApplicationController < ActionController::Base
122
+ def pjax_layout
123
+ 'peek'
124
+ end
125
+ end
126
+ ```
127
+
128
+ You're done! Now every time a PJAX request is made, the Peek bar will update
129
+ with the Peek results of the PJAX request.
130
+
131
+ ## Using Peek with Turbolinks
132
+
133
+ It just works.
134
+
135
+ ## Access Control
136
+
137
+ You probably don't want to give this data to ALL your users. So by default Peek
138
+ only shows up in development or staging environments. If you'd like to restrict Peek
139
+ to a select few users, you can do so by overriding the `peek_enabled?` guard in
140
+ ApplicationController.
141
+
142
+ ```ruby
143
+ class ApplicationController < ActionController::Base
144
+ def peek_enabled?
145
+ current_user.staff?
146
+ end
147
+ end
148
+ ```
149
+
150
+ ## Available Peek items
151
+
152
+ - [peek-dalli](https://github.com/peek/peek-dalli)
153
+ - [peek-git](https://github.com/peek/peek-git)
154
+ - [peek-mongo](https://github.com/peek/peek-mongo)
155
+ - [peek-mysql2](https://github.com/peek/peek-mysql2)
156
+ - [peek-performance_bar](https://github.com/peek/peek-performance_bar)
157
+ - [peek-pg](https://github.com/peek/peek-pg)
158
+ - [peek-redis](https://github.com/peek/peek-redis)
159
+ - [peek-resque](https://github.com/peek/peek-resque)
160
+ - [glimpse-sidekiq](https://github.com/suranyami/glimpse-sidekiq)
161
+ - [glimpse-svn](https://github.com/neilco/glimpse-svn)
162
+ - Unicorn :soon:
163
+
164
+ Feel free to submit a Pull Request adding your own Peek item to this list.
165
+
166
+ ## Creating your own Peek item
167
+
168
+ Each Peek item is a self contained Rails engine which gives you the power to
169
+ use all features of Ruby on Rails to dig in deep within your application and
170
+ report it back to the Peek bar. A Peek item is just a custom class that
171
+ is responsible for fetching and building the data that should be reported back
172
+ to the user.
173
+
174
+ There are still some docs to be written, but if you'd like to checkout a simple
175
+ example of how to create your own, just checkout [peek-git](https://github.com/peek/peek-git).
176
+ To just look at an example view, there is [Peek::Views::Git](https://github.com/peek/peek-git/blob/master/lib/peek/views/git.rb).
177
+
178
+ ### Using Peek with Spork
179
+
180
+ For best results with Spork, add this to your `prefork` block
181
+ anytime before your environment is loaded:
182
+
183
+ ```ruby
184
+ Spork.trap_class_method(Peek, :setup)
185
+ ```
186
+
187
+ ## Contributing
188
+
189
+ 1. Fork it
190
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
191
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
192
+ 4. Push to the branch (`git push origin my-new-feature`)
193
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ desc 'Default: run tests'
5
+ task :default => :test
6
+
7
+ desc 'Run Peek tests.'
8
+ Rake::TestTask.new do |t|
9
+ t.libs << 'lib'
10
+ t.libs << 'test'
11
+ t.test_files = FileList['test/**/*_test.rb']
12
+ t.verbose = true
13
+ end
@@ -0,0 +1,258 @@
1
+ // tipsy, facebook style tooltips for jquery
2
+ // version 1.0.0a
3
+ // (c) 2008-2010 jason frame [jason@onehackoranother.com]
4
+ // released under the MIT license
5
+
6
+ (function($) {
7
+
8
+ function maybeCall(thing, ctx) {
9
+ return (typeof thing == 'function') ? (thing.call(ctx)) : thing;
10
+ };
11
+
12
+ function isElementInDOM(ele) {
13
+ while (ele = ele.parentNode) {
14
+ if (ele == document) return true;
15
+ }
16
+ return false;
17
+ };
18
+
19
+ function Tipsy(element, options) {
20
+ this.$element = $(element);
21
+ this.options = options;
22
+ this.enabled = true;
23
+ this.fixTitle();
24
+ };
25
+
26
+ Tipsy.prototype = {
27
+ show: function() {
28
+ var title = this.getTitle();
29
+ if (title && this.enabled) {
30
+ var $tip = this.tip();
31
+
32
+ $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title);
33
+ $tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity
34
+ $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).prependTo(document.body);
35
+
36
+ var pos = $.extend({}, this.$element.offset(), {
37
+ width: this.$element[0].offsetWidth,
38
+ height: this.$element[0].offsetHeight
39
+ });
40
+
41
+ var actualWidth = $tip[0].offsetWidth,
42
+ actualHeight = $tip[0].offsetHeight,
43
+ gravity = maybeCall(this.options.gravity, this.$element[0]);
44
+
45
+ var tp;
46
+ switch (gravity.charAt(0)) {
47
+ case 'n':
48
+ tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
49
+ break;
50
+ case 's':
51
+ tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
52
+ break;
53
+ case 'e':
54
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset};
55
+ break;
56
+ case 'w':
57
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset};
58
+ break;
59
+ }
60
+
61
+ if (gravity.length == 2) {
62
+ if (gravity.charAt(1) == 'w') {
63
+ tp.left = pos.left + pos.width / 2 - 15;
64
+ } else {
65
+ tp.left = pos.left + pos.width / 2 - actualWidth + 15;
66
+ }
67
+ }
68
+
69
+ $tip.css(tp).addClass('tipsy-' + gravity);
70
+ $tip.find('.tipsy-arrow')[0].className = 'tipsy-arrow tipsy-arrow-' + gravity.charAt(0);
71
+ if (this.options.className) {
72
+ $tip.addClass(maybeCall(this.options.className, this.$element[0]));
73
+ }
74
+
75
+ if (this.options.fade) {
76
+ $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity});
77
+ } else {
78
+ $tip.css({visibility: 'visible', opacity: this.options.opacity});
79
+ }
80
+ }
81
+ },
82
+
83
+ hide: function() {
84
+ if (this.options.fade) {
85
+ this.tip().stop().fadeOut(function() { $(this).remove(); });
86
+ } else {
87
+ this.tip().remove();
88
+ }
89
+ },
90
+
91
+ fixTitle: function() {
92
+ var $e = this.$element;
93
+ if ($e.attr('title') || typeof($e.attr('original-title')) != 'string') {
94
+ $e.attr('original-title', $e.attr('title') || '').removeAttr('title');
95
+ }
96
+ },
97
+
98
+ getTitle: function() {
99
+ var title, $e = this.$element, o = this.options;
100
+ this.fixTitle();
101
+ var title, o = this.options;
102
+ if (typeof o.title == 'string') {
103
+ title = $e.attr(o.title == 'title' ? 'original-title' : o.title);
104
+ } else if (typeof o.title == 'function') {
105
+ title = o.title.call($e[0]);
106
+ }
107
+ title = ('' + title).replace(/(^\s*|\s*$)/, "");
108
+ return title || o.fallback;
109
+ },
110
+
111
+ tip: function() {
112
+ if (!this.$tip) {
113
+ this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
114
+ this.$tip.data('tipsy-pointee', this.$element[0]);
115
+ }
116
+ return this.$tip;
117
+ },
118
+
119
+ validate: function() {
120
+ if (!this.$element[0].parentNode) {
121
+ this.hide();
122
+ this.$element = null;
123
+ this.options = null;
124
+ }
125
+ },
126
+
127
+ enable: function() { this.enabled = true; },
128
+ disable: function() { this.enabled = false; },
129
+ toggleEnabled: function() { this.enabled = !this.enabled; }
130
+ };
131
+
132
+ $.fn.tipsy = function(options) {
133
+
134
+ if (options === true) {
135
+ return this.data('tipsy');
136
+ } else if (typeof options == 'string') {
137
+ var tipsy = this.data('tipsy');
138
+ if (tipsy) tipsy[options]();
139
+ return this;
140
+ }
141
+
142
+ options = $.extend({}, $.fn.tipsy.defaults, options);
143
+
144
+ function get(ele) {
145
+ var tipsy = $.data(ele, 'tipsy');
146
+ if (!tipsy) {
147
+ tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options));
148
+ $.data(ele, 'tipsy', tipsy);
149
+ }
150
+ return tipsy;
151
+ }
152
+
153
+ function enter() {
154
+ var tipsy = get(this);
155
+ tipsy.hoverState = 'in';
156
+ if (options.delayIn == 0) {
157
+ tipsy.show();
158
+ } else {
159
+ tipsy.fixTitle();
160
+ setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn);
161
+ }
162
+ };
163
+
164
+ function leave() {
165
+ var tipsy = get(this);
166
+ tipsy.hoverState = 'out';
167
+ if (options.delayOut == 0) {
168
+ tipsy.hide();
169
+ } else {
170
+ setTimeout(function() { if (tipsy.hoverState == 'out') tipsy.hide(); }, options.delayOut);
171
+ }
172
+ };
173
+
174
+ if (!options.live) this.each(function() { get(this); });
175
+
176
+ if (options.trigger != 'manual') {
177
+ var binder = options.live ? 'live' : 'bind',
178
+ eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus',
179
+ eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur';
180
+ this[binder](eventIn, enter)[binder](eventOut, leave);
181
+ }
182
+
183
+ return this;
184
+
185
+ };
186
+
187
+ $.fn.tipsy.defaults = {
188
+ className: null,
189
+ delayIn: 0,
190
+ delayOut: 0,
191
+ fade: false,
192
+ fallback: '',
193
+ gravity: 'n',
194
+ html: false,
195
+ live: false,
196
+ offset: 0,
197
+ opacity: 0.8,
198
+ title: 'title',
199
+ trigger: 'hover'
200
+ };
201
+
202
+ $.fn.tipsy.revalidate = function() {
203
+ $('.tipsy').each(function() {
204
+ var pointee = $.data(this, 'tipsy-pointee');
205
+ if (!pointee || !isElementInDOM(pointee)) {
206
+ $(this).remove();
207
+ }
208
+ });
209
+ };
210
+
211
+ // Overwrite this method to provide options on a per-element basis.
212
+ // For example, you could store the gravity in a 'tipsy-gravity' attribute:
213
+ // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' });
214
+ // (remember - do not modify 'options' in place!)
215
+ $.fn.tipsy.elementOptions = function(ele, options) {
216
+ return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
217
+ };
218
+
219
+ $.fn.tipsy.autoNS = function() {
220
+ return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n';
221
+ };
222
+
223
+ $.fn.tipsy.autoWE = function() {
224
+ return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w';
225
+ };
226
+
227
+ /**
228
+ * yields a closure of the supplied parameters, producing a function that takes
229
+ * no arguments and is suitable for use as an autogravity function like so:
230
+ *
231
+ * @param margin (int) - distance from the viewable region edge that an
232
+ * element should be before setting its tooltip's gravity to be away
233
+ * from that edge.
234
+ * @param prefer (string, e.g. 'n', 'sw', 'w') - the direction to prefer
235
+ * if there are no viewable region edges effecting the tooltip's
236
+ * gravity. It will try to vary from this minimally, for example,
237
+ * if 'sw' is preferred and an element is near the right viewable
238
+ * region edge, but not the top edge, it will set the gravity for
239
+ * that element's tooltip to be 'se', preserving the southern
240
+ * component.
241
+ */
242
+ $.fn.tipsy.autoBounds = function(margin, prefer) {
243
+ return function() {
244
+ var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)},
245
+ boundTop = $(document).scrollTop() + margin,
246
+ boundLeft = $(document).scrollLeft() + margin,
247
+ $this = $(this);
248
+
249
+ if ($this.offset().top < boundTop) dir.ns = 'n';
250
+ if ($this.offset().left < boundLeft) dir.ew = 'w';
251
+ if ($(window).width() + $(document).scrollLeft() - $this.offset().left < margin) dir.ew = 'e';
252
+ if ($(window).height() + $(document).scrollTop() - $this.offset().top < margin) dir.ns = 's';
253
+
254
+ return dir.ns + (dir.ew ? dir.ew : '');
255
+ }
256
+ };
257
+
258
+ })(jQuery);
@@ -0,0 +1,43 @@
1
+ #= require peek/vendor/jquery.tipsy
2
+
3
+ updatePerformanceBar = ->
4
+ peekResults = $('#peek-results')
5
+ $('#peek [data-defer-to]').each ->
6
+ deferKey = $(this).data 'defer-to'
7
+ data = peekResults.data deferKey
8
+ $(this).text data
9
+
10
+ initializeTipsy = ->
11
+ $('#peek .peek-tooltip, #peek .tooltip').each ->
12
+ el = $(this)
13
+ gravity = if el.hasClass('rightwards') then 'w' else 'n'
14
+ gravity = if el.hasClass('leftwards') then 'e' else gravity
15
+ el.tipsy { gravity }
16
+
17
+ toggleBar = (event) ->
18
+ return if $(event.target).is ':input'
19
+
20
+ if event.keyCode == 96 && !event.metaKey
21
+ wrapper = $('#peek')
22
+ if wrapper.hasClass 'disabled'
23
+ wrapper.removeClass 'disabled'
24
+ document.cookie = "peek=true; path=/";
25
+ else
26
+ wrapper.addClass 'disabled'
27
+ document.cookie = "peek=false; path=/";
28
+
29
+ $(document).on 'keypress', toggleBar
30
+
31
+ $(document).on 'peek:update', updatePerformanceBar
32
+ $(document).on 'peek:update', initializeTipsy
33
+
34
+ # Fire the event for our own listeners.
35
+ $(document).on 'pjax:end', ->
36
+ $(this).trigger 'peek:update'
37
+
38
+ # Also listen to turbolinks page change event
39
+ $(document).on 'page:change', ->
40
+ $(this).trigger 'peek:update'
41
+
42
+ $ ->
43
+ $(this).trigger 'peek:update'
@@ -0,0 +1,22 @@
1
+ .tipsy { font-size: 10px; position: absolute; padding: 5px; z-index: 100000; }
2
+ .tipsy-inner { background-color: #000; color: #FFF; max-width: 200px; padding: 5px 8px 4px 8px; text-align: center; }
3
+
4
+ /* Rounded corners */
5
+ .tipsy-inner { border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; }
6
+
7
+ .tipsy-arrow { position: absolute; width: 0; height: 0; line-height: 0; border: 5px dashed #000; }
8
+
9
+ /* Rules to colour arrows */
10
+ .tipsy-arrow-n { border-bottom-color: #000; }
11
+ .tipsy-arrow-s { border-top-color: #000; }
12
+ .tipsy-arrow-e { border-left-color: #000; }
13
+ .tipsy-arrow-w { border-right-color: #000; }
14
+
15
+ .tipsy-n .tipsy-arrow { top: 0px; left: 50%; margin-left: -5px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent; }
16
+ .tipsy-nw .tipsy-arrow { top: 0; left: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
17
+ .tipsy-ne .tipsy-arrow { top: 0; right: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
18
+ .tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
19
+ .tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
20
+ .tipsy-se .tipsy-arrow { bottom: 0; right: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
21
+ .tipsy-e .tipsy-arrow { right: 0; top: 50%; margin-top: -5px; border-left-style: solid; border-right: none; border-top-color: transparent; border-bottom-color: transparent; }
22
+ .tipsy-w .tipsy-arrow { left: 0; top: 50%; margin-top: -5px; border-right-style: solid; border-left: none; border-top-color: transparent; border-bottom-color: transparent; }
@@ -0,0 +1,68 @@
1
+ //= require peek/vendor/tipsy
2
+
3
+ #peek {
4
+ background: #000;
5
+ height: 35px;
6
+ line-height: 35px;
7
+ color: #999;
8
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
9
+
10
+ .hidden {
11
+ display: none;
12
+ visibility: visible;
13
+ }
14
+
15
+ &.disabled {
16
+ display: none;
17
+ }
18
+
19
+ &.production {
20
+ background: image-url('peek/bar/production.gif') repeat 0 0;
21
+ }
22
+
23
+ &.staging {
24
+ background: image-url('peek/bar/staging.gif') repeat 0 0;
25
+ }
26
+
27
+ &.development {
28
+ background: image-url('peek/bar/development.gif') repeat 0 0;
29
+ }
30
+
31
+ .wrapper {
32
+ width: 800px;
33
+ margin: 0 auto;
34
+ }
35
+
36
+ // UI Elements
37
+ .bucket {
38
+ background: #111;
39
+ display: inline-block;
40
+ padding: 4px 6px;
41
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
42
+ line-height: 1;
43
+ color: #ccc;
44
+ border-radius: 3px;
45
+ box-shadow: 0 1px 0 rgba(255,255,255,.2), inset 0 1px 2px rgba(0,0,0,.25);
46
+
47
+ .hidden {
48
+ display: none;
49
+ }
50
+
51
+ &:hover .hidden {
52
+ display: inline;
53
+ }
54
+ }
55
+
56
+ strong {
57
+ color: #fff;
58
+ }
59
+
60
+ .view {
61
+ margin-right: 15px;
62
+ float: left;
63
+
64
+ &:last-child {
65
+ margin-right: 0;
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,11 @@
1
+ <% if peek_enabled? %>
2
+ <div id="peek" class="<%= Peek.env %><%= ' disabled' if cookies[:peek] == 'false' %>">
3
+ <div class="wrapper">
4
+ <% Peek.views.each do |view| %>
5
+ <div id="<%= view.dom_id %>" class="view">
6
+ <%= render view.partial_path, :view => view %>
7
+ </div>
8
+ <% end %>
9
+ </div>
10
+ </div>
11
+ <% end %>
@@ -0,0 +1,16 @@
1
+ <% if peek_enabled? %>
2
+ <span id="peek-results" class="hidden"
3
+ <% Peek.views.each do |view| %>
4
+ <% view.results.each do |key, value| %>
5
+ data-<%= view.defer_key %>-<%= key %>="<%= value %>"
6
+ <% end %>
7
+ <% end %>
8
+ >
9
+ </span>
10
+
11
+ <% Peek.views.each do |view| %>
12
+ <% if view.context? %>
13
+ <span id="<%= view.context_dom_id %>" data-context='<%= raw(view.context.to_json) %>'></span>
14
+ <% end %>
15
+ <% end %>
16
+ <% end %>
@@ -0,0 +1,15 @@
1
+ module Peek
2
+ module ControllerHelpers
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ helper_method :peek_enabled?
7
+ end
8
+
9
+ protected
10
+
11
+ def peek_enabled?
12
+ Peek.enabled?
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require 'peek/controller_helpers'
2
+
3
+ module Peek
4
+ class Railtie < ::Rails::Engine
5
+ config.peek = Peek
6
+
7
+ initializer 'peek.setup_subscribers' do
8
+ ActiveSupport.on_load(:after_initialize) do
9
+ Peek.views
10
+ end
11
+ end
12
+
13
+ initializer 'peek.include_controller_helpers' do
14
+ config.to_prepare do
15
+ Peek.setup
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Peek
2
+ VERSION = '0.0.5'
3
+ end
@@ -0,0 +1,106 @@
1
+ module Peek
2
+ module Views
3
+ class View
4
+ def initialize(options = {})
5
+ @options = options
6
+
7
+ setup_subscribers
8
+ end
9
+
10
+ # Conditionally enable views based on any gathered data. Helpful
11
+ # if you don't want views to show up when they return 0 or are
12
+ # touched during the request.
13
+ #
14
+ # Returns true.
15
+ def enabled?
16
+ true
17
+ end
18
+
19
+ # The path to the partial that will be rendered to the Peek bar.
20
+ #
21
+ # Examples:
22
+ #
23
+ # Peek::Views::PerformanceBar.partial_path => "peek/views/performance_bar"
24
+ # CustomResque.partial_path => "performance_bar"
25
+ #
26
+ # Returns String.
27
+ def partial_path
28
+ self.class.to_s.underscore
29
+ end
30
+
31
+ # The defer key that is derived from the classname.
32
+ #
33
+ # Examples:
34
+ #
35
+ # Peek::Views::PerformanceBar => "performance-bar"
36
+ # Peek::Views::Resque => "resque"
37
+ #
38
+ # Returns String.
39
+ def defer_key
40
+ self.class.to_s.split('::').last.underscore.gsub(/\_/, '-')
41
+ end
42
+
43
+ # The context dom id that is derived from the classname.
44
+ #
45
+ # Examples:
46
+ #
47
+ # Peek::Views::PerformanceBar => "peek-context-performance-bar"
48
+ # Peek::Views::Resque => "peek-context-resque"
49
+ #
50
+ # Returns String.
51
+ def context_dom_id
52
+ "peek-context-#{defer_key}"
53
+ end
54
+
55
+ # The wrapper ID for the individual view in the Peek bar.
56
+ #
57
+ # Returns String.
58
+ def dom_id
59
+ "peek-view-#{defer_key}"
60
+ end
61
+
62
+ # Additional context for any view to render tooltips for.
63
+ #
64
+ # Returns Hash.
65
+ def context
66
+ {}
67
+ end
68
+
69
+ def context?
70
+ context.any?
71
+ end
72
+
73
+ # The data results that are inserted at the end of the request for use in
74
+ # deferred placeholders in the Peek the bar.
75
+ #
76
+ # Returns Hash.
77
+ def results
78
+ {}
79
+ end
80
+
81
+ def results?
82
+ results.any?
83
+ end
84
+
85
+ def subscribe(*args)
86
+ ActiveSupport::Notifications.subscribe(*args) do |name, start, finish, id, payload|
87
+ yield name, start, finish, id, payload
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def setup_subscribers
94
+ # pass
95
+ end
96
+
97
+ # Helper method for subscribing to the event that is fired when new
98
+ # requests are made.
99
+ def before_request
100
+ subscribe 'start_processing.action_controller' do |name, start, finish, id, payload|
101
+ yield name, start, finish, id, payload
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
data/lib/peek.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'peek/version'
2
+ require 'rails'
3
+
4
+ require 'peek/views/view'
5
+ Dir[File.join(File.dirname(__FILE__), 'peek', 'views', '*.rb')].each do |view|
6
+ require view
7
+ end
8
+
9
+ module Peek
10
+ def self.enabled?
11
+ ['development', 'staging'].include?(env)
12
+ end
13
+
14
+ def self.env
15
+ Rails.env
16
+ end
17
+
18
+ def self.views
19
+ @cached_views ||= if @views && @views.any?
20
+ @views.collect { |klass, options| klass.new(options.dup) }.select(&:enabled?)
21
+ else
22
+ []
23
+ end
24
+ end
25
+
26
+ def self.into(klass, options = {})
27
+ @views ||= []
28
+ @views << [klass, options]
29
+ end
30
+
31
+ def self.reset
32
+ @views = nil
33
+ @cached_views = nil
34
+ end
35
+
36
+ def self.setup
37
+ ApplicationController.send(:include, Peek::ControllerHelpers)
38
+ end
39
+ end
40
+
41
+ require 'peek/railtie'
data/peek.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'peek/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'peek'
8
+ gem.version = Peek::VERSION
9
+ gem.authors = ['Garrett Bjerkhoel']
10
+ gem.email = ['me@garrettbjerkhoel.com']
11
+ gem.description = %q{Take a peek into your Rails application.}
12
+ gem.summary = %q{Take a peek into your Rails application.}
13
+ gem.homepage = 'https://github.com/dewski/peek'
14
+ gem.license = 'MIT'
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ['lib']
20
+
21
+ gem.add_dependency 'rails', '>= 3'
22
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ describe Peek::Views::View do
4
+ before do
5
+ @view = Peek::Views::View.new
6
+ end
7
+
8
+ describe "partial path" do
9
+ it "should return correct partial class" do
10
+ assert_equal 'peek/views/view', @view.partial_path
11
+ end
12
+ end
13
+
14
+ describe "dom_id" do
15
+ it "should return correct dom_id" do
16
+ assert_equal 'peek-view-view', @view.dom_id
17
+ end
18
+ end
19
+
20
+ describe "defer_key" do
21
+ it "should return correct defer_key" do
22
+ assert_equal 'view', @view.defer_key
23
+ end
24
+ end
25
+
26
+ describe "context" do
27
+ it "should return correct context_dom_id" do
28
+ assert_equal 'peek-context-view', @view.context_dom_id
29
+ end
30
+ end
31
+
32
+ describe "toggling off and on" do
33
+ it "should be enabled by default" do
34
+ assert @view.enabled?
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,69 @@
1
+ require 'test_helper'
2
+
3
+ class Staff < Peek::Views::View
4
+ def initialize(options = {})
5
+ @username = options.delete(:username)
6
+ end
7
+
8
+ def username
9
+ @username
10
+ end
11
+
12
+ def enabled?
13
+ !!@username
14
+ end
15
+ end
16
+
17
+ describe Peek do
18
+ describe "enabled?" do
19
+ it "should not be enabled in test" do
20
+ refute Peek.enabled?
21
+ end
22
+ end
23
+
24
+ describe "env" do
25
+ it "should return the current environment" do
26
+ assert_equal 'test', Peek.env
27
+ end
28
+ end
29
+
30
+ describe "views" do
31
+ before do
32
+ Peek.reset
33
+ end
34
+
35
+ it "should have none by default" do
36
+ assert_equal [], Peek.views
37
+ end
38
+
39
+ it "should be able to append views" do
40
+ Peek.into Staff, :username => 'dewski'
41
+ assert_kind_of Staff, Peek.views.first
42
+ end
43
+
44
+ it "should be able to append views with options" do
45
+ Peek.into Staff, :username => 'dewski'
46
+ @staff = Peek.views.first
47
+ assert_kind_of Staff, @staff
48
+ assert_equal 'dewski', @staff.username
49
+ end
50
+
51
+ it "should only return enabled views" do
52
+ Peek.into Staff, :username => false
53
+ assert_equal [], Peek.views
54
+ end
55
+ end
56
+
57
+ describe "reset" do
58
+ before do
59
+ Peek.reset
60
+ end
61
+
62
+ it "should clear any current views" do
63
+ Peek.into Staff, :username => 'dewski'
64
+ assert_kind_of Staff, Peek.views.first
65
+ Peek.reset
66
+ assert_equal [], Peek.views
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,11 @@
1
+ ENV['RAILS_ENV'] = "test"
2
+
3
+ require 'peek'
4
+
5
+ require 'minitest/autorun'
6
+
7
+ begin
8
+ require 'turn'
9
+ rescue LoadError
10
+ # Not installed.
11
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: peek
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Garrett Bjerkhoel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3'
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: '3'
30
+ description: Take a peek into your Rails application.
31
+ email:
32
+ - me@garrettbjerkhoel.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - CHANGELOG.md
39
+ - Gemfile
40
+ - LICENSE.txt
41
+ - README.md
42
+ - Rakefile
43
+ - app/assets/images/peek/bar/development.gif
44
+ - app/assets/images/peek/bar/production.gif
45
+ - app/assets/images/peek/bar/staging.gif
46
+ - app/assets/javascripts/peek.coffee
47
+ - app/assets/javascripts/peek/vendor/jquery.tipsy.js
48
+ - app/assets/stylesheets/peek.scss
49
+ - app/assets/stylesheets/peek/vendor/tipsy.scss
50
+ - app/views/peek/_bar.html.erb
51
+ - app/views/peek/_results.html.erb
52
+ - lib/peek.rb
53
+ - lib/peek/controller_helpers.rb
54
+ - lib/peek/railtie.rb
55
+ - lib/peek/version.rb
56
+ - lib/peek/views/view.rb
57
+ - peek.gemspec
58
+ - test/glimpse/views/view_test.rb
59
+ - test/glimpse_test.rb
60
+ - test/test_helper.rb
61
+ homepage: https://github.com/dewski/peek
62
+ licenses:
63
+ - MIT
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 1.8.23
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Take a peek into your Rails application.
86
+ test_files:
87
+ - test/glimpse/views/view_test.rb
88
+ - test/glimpse_test.rb
89
+ - test/test_helper.rb