rack-webconsole 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 ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ pkg/*
4
+ graph.png
5
+ .yardoc/*
6
+ doc/*
7
+ coverage/*
8
+ *.rbc
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use ruby-1.9.2@rack-webconsole
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rack-webconsole.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rack-webconsole (0.0.1)
5
+ json
6
+ rack
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ bluecloth (2.1.0)
12
+ json (1.5.3)
13
+ minitest (2.3.1)
14
+ mocha (0.9.12)
15
+ purdytest (1.0.0)
16
+ minitest (~> 2.2)
17
+ rack (1.3.1)
18
+ rake (0.9.2)
19
+ yard (0.7.2)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ bluecloth
26
+ minitest
27
+ mocha
28
+ purdytest
29
+ rack-webconsole!
30
+ rake
31
+ yard
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ desc "Run rack-webconsole specs"
6
+ Rake::TestTask.new do |t|
7
+ t.libs << "spec"
8
+ t.test_files = FileList['spec/**/*_spec.rb']
9
+ t.verbose = true
10
+ end
11
+
12
+ require 'yard'
13
+ YARD::Rake::YardocTask.new(:docs) do |t|
14
+ t.files = ['lib/**/*.rb']
15
+ t.options = ['-m', 'markdown', '--no-private', '-r', 'Readme.md', '--title', 'rack-webconsole documentation']
16
+ end
17
+
18
+ task :doc => [:docs]
19
+
20
+ desc "Generate and open class diagram (needs Graphviz installed)"
21
+ task :graph do |t|
22
+ `bundle exec yard graph -d --full --no-private | dot -Tpng -o graph.png && open graph.png`
23
+ end
24
+
25
+ task :default => [:test]
data/Readme.md ADDED
@@ -0,0 +1,87 @@
1
+ #rack-webconsole
2
+
3
+ Rack-webconsole is a Rack-based interactive console (à la Rails console) in
4
+ your web application's frontend. That means you can interact with your
5
+ application's backend from within the browser itself!
6
+
7
+ To get a clearer idea, you can check out [this video](
8
+ http://youtu.be/yKK5J01Dqts?hd=1) showing a live example :)
9
+
10
+ Rack-webconsole is a Rack middleware designed to be unobtrusive. With Rails 3,
11
+ for example, you only have to include the gem in your Gemfile and it already
12
+ works. Without any configuration.
13
+
14
+ Tested with MRI 1.9.2 and ruby-head (1.9.3).
15
+
16
+ ##Resources
17
+
18
+ * [Example video](http://youtu.be/yKK5J01Dqts?hd=1)
19
+ * [Documentation](http://rubydoc.info/github/codegram/rack-webconsole)
20
+
21
+ ##Install
22
+
23
+ In your Gemfile:
24
+
25
+ gem 'rack-webconsole'
26
+
27
+
28
+ ##Usage with Rails 3
29
+
30
+ If you are using Rails 3, you have no further steps to do. It works! To give
31
+ it a try, fire up the Rails server and go to any page, press the ` ` ` key and
32
+ the console will show :)
33
+
34
+ ##Usage with Sinatra/Padrino
35
+
36
+ With Sinatra and Padrino you have to tell your application to use the
37
+ middleware:
38
+
39
+ require 'sinatra'
40
+ require 'rack/webconsole'
41
+
42
+ class MySinatraApp < Sinatra::Application
43
+ use Rack::Webconsole
44
+ # . . .
45
+ end
46
+
47
+ class SamplePadrino < Padrino::Application
48
+ use Rack::Webconsole
49
+ # . . .
50
+ end
51
+
52
+ NOTE: If you are using Bundler and initializing it from config.ru, you don't
53
+ have to `require 'rack/webconsole'` manually, otherwise you have to.
54
+
55
+ And it works! Fire up the server, go to any page and press the ` ` ` key.
56
+
57
+ ##Commands
58
+
59
+ In the console you can issue whatever Ruby commands you want, except multiline commands. Local variables are kept, so you can get a more IRB-esque feeling.
60
+
61
+ To reset all local variables, just issue the `reload!` command.
62
+
63
+ ##Under the hood
64
+
65
+ Run the test suite by typing:
66
+
67
+ rake
68
+
69
+ You can also build the documentation with the following command:
70
+
71
+ rake docs
72
+
73
+ ## Note on Patches/Pull Requests
74
+
75
+ * Fork the project.
76
+ * Make your feature addition or bug fix.
77
+ * Add tests for it. This is important so I don't break it in a
78
+ future version unintentionally.
79
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
80
+ * Send us a pull request. Bonus points for topic branches.
81
+
82
+ ## Copyright
83
+
84
+ Copyright (c) 2011 Codegram. See LICENSE for details.
85
+
86
+
87
+
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+ module Rack
3
+ class Webconsole
4
+ # Helper module to encapsulate the asset loading logic used by the {Assets}
5
+ # middleware.
6
+ #
7
+ # For now, the strategy is reading the files from disk. In the future, we
8
+ # should come up with a somewhat more sophisticated strategy, although
9
+ # {Webconsole} is used only in development environments, where performance
10
+ # isn't usually a concern.
11
+ #
12
+ module AssetHelpers
13
+ # Loads the HTML from a file in `/public`.
14
+ #
15
+ # It contains a form and the needed divs to render the console.
16
+ #
17
+ # @return [String] the injectable HTML.
18
+ def html_code
19
+ asset 'webconsole.html'
20
+ end
21
+
22
+ # Loads the CSS from a file in `/public`.
23
+ #
24
+ # It contains the styles for the console.
25
+ #
26
+ # @return [String] the injectable CSS.
27
+ def css_code
28
+ '<style type="text/css">' <<
29
+ asset('webconsole.css') <<
30
+ '</style>'
31
+ end
32
+
33
+ # Loads the JavaScript from a file in `/public`.
34
+ #
35
+ # It contains the JavaScript logic of the webconsole.
36
+ #
37
+ # @return [String] the injectable JavaScript.
38
+ def js_code
39
+ '<script type="text/javascript">' <<
40
+ asset('webconsole.js') <<
41
+ '</script>'
42
+ end
43
+
44
+ private
45
+
46
+ def asset(file)
47
+ ::File.read(::File.join(::File.dirname(__FILE__), '..', '..', '..', 'public', file))
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ module Rack
3
+ class Webconsole
4
+ # {Assets} is a Rack middleware responsible for injecting view code for the
5
+ # console to work properly.
6
+ #
7
+ # It intercepts HTTP requests, detects successful HTML responses and
8
+ # injects HTML, CSS and JavaScript code into those.
9
+ #
10
+ class Assets
11
+ include Webconsole::AssetHelpers
12
+
13
+ # Honor the Rack contract by saving the passed Rack application in an ivar.
14
+ #
15
+ # @param [Rack::Application] app the previous Rack application in the
16
+ # middleware chain.
17
+ def initialize(app)
18
+ @app = app
19
+ end
20
+
21
+ # Checks for successful HTML responses and injects HTML, CSS and
22
+ # JavaScript code into them.
23
+ #
24
+ # @param [Hash] env a Rack request environment.
25
+ def call(env)
26
+ status, headers, response = @app.call(env)
27
+ return [status, headers, response] unless check_html?(headers, response) && status == 200
28
+
29
+ if response.respond_to?(:body)
30
+ response_body = response.body
31
+ else
32
+ response_body = response.first
33
+ end
34
+
35
+ # Inject the html, css and js code to the view
36
+ response_body.gsub!('</body>', "#{code}</body>")
37
+ headers['Content-Length'] = (response_body.length + 2).to_s
38
+
39
+ [status, headers, [response_body]]
40
+ end
41
+
42
+ # Returns a string with all the HTML, CSS and JavaScript code needed for
43
+ # the view.
44
+ #
45
+ # @return [String] the injectable code.
46
+ def code
47
+ html_code << css_code << js_code
48
+ end
49
+
50
+ private
51
+
52
+ def check_html?(headers, response)
53
+ body = response.respond_to?(:body) ? response.body : response.first
54
+ headers['Content-Type'] and
55
+ headers['Content-Type'].include? 'text/html' and
56
+ body =~ %r{<html.*</html>}m
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ module Rack
3
+ class Webconsole
4
+ # Railtie loaded in Rails applications. Its purpose is to automatically use
5
+ # the middleware in development environment, so that Rails users only have
6
+ # to require 'rack-webconsole' in their Gemfile and nothing more than that.
7
+ #
8
+ class Railtie < Rails::Railtie
9
+ initializer 'rack-webconsole.add_middleware' do |app|
10
+ app.middleware.use Rack::Webconsole if Rails.env.development?
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+ require 'json'
3
+ module Rack
4
+ class Webconsole
5
+ # {Repl} is a Rack middleware acting as a Ruby evaluator application.
6
+ #
7
+ # In a nutshell, it evaluates a string in a {Sandbox} instance stored in an
8
+ # evil global variable. Then, to keep the state, it inspects the local
9
+ # variables and stores them in an instance variable for further retrieval.
10
+ #
11
+ class Repl
12
+ # Honor the Rack contract by saving the passed Rack application in an ivar.
13
+ #
14
+ # @param [Rack::Application] app the previous Rack application in the
15
+ # middleware chain.
16
+ def initialize(app)
17
+ @app = app
18
+ end
19
+
20
+ # Evaluates a string as Ruby code and returns the evaluated result as
21
+ # JSON.
22
+ #
23
+ # It also stores the {Sandbox} state in a `$sandbox` global variable, with
24
+ # its local variables.
25
+ #
26
+ # @param [Hash] env the Rack request environment.
27
+ # @return [Array] a Rack response with status code 200, HTTP headers
28
+ # and the evaluated Ruby result.
29
+ def call(env)
30
+ status, headers, response = @app.call(env)
31
+
32
+ req = Rack::Request.new(env)
33
+
34
+ params = req.params
35
+
36
+ result = begin
37
+ $sandbox ||= Sandbox.new
38
+
39
+ boilerplate = local_variables + [:ls]
40
+
41
+ result = $sandbox.instance_eval """
42
+ result = (#{params['query']})
43
+ ls = (local_variables - #{boilerplate})
44
+ @locals ||= {}
45
+ @locals.update(ls.inject({}) do |hash, value|
46
+ hash.update({value => eval(value.to_s)})
47
+ end)
48
+ result
49
+ """
50
+
51
+ result.inspect
52
+ rescue=>e
53
+ "Error: " + e.message
54
+ end
55
+ response_body = {:result => result}.to_json
56
+ headers = {}
57
+ headers['Content-Type'] = 'application/json'
58
+ headers['Content-Length'] = response_body.length.to_s
59
+ [200, headers, [response_body]]
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ module Rack
3
+ class Webconsole
4
+ # A sandbox to evaluate Ruby in. It is responsible for retrieving local
5
+ # variables stored in `@locals`, and resetting the environment.
6
+ #
7
+ class Sandbox
8
+ # Catches all the undefined local variables and tries to retrieve them
9
+ # from `@locals`. If it doesn't find them, it falls back to the default
10
+ # method missing behavior.
11
+ def method_missing(method, *args, &block)
12
+ @locals ||= {}
13
+ @locals[method] || super(method, *args, &block)
14
+ end
15
+
16
+ # Makes the console use a fresh, new {Sandbox} with all local variables
17
+ # resetted.
18
+ #
19
+ # @return [String] 'ok' to make the user notice.
20
+ def reload!
21
+ $sandbox = Sandbox.new
22
+ 'ok'
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ module Rack
3
+ class Webconsole
4
+ # rack-webconsole version number.
5
+ VERSION = "0.0.1"
6
+ end
7
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ require 'rack/webconsole/repl'
3
+ require 'rack/webconsole/asset_helpers'
4
+ require 'rack/webconsole/assets'
5
+ require 'rack/webconsole/sandbox'
6
+
7
+ require 'rack/webconsole/railtie' if defined?(Rails)
8
+
9
+ # Rack is a modular webserver interface written by Christian Neukirchen.
10
+ #
11
+ # Learn more at: https://github.com/rack/rack
12
+ #
13
+ module Rack
14
+ # {Rack::Webconsole} is a Rack middleware that provides an interactive
15
+ # console à la Rails console, but for any kind of Rack application (Rails,
16
+ # Sinatra, Padrino...), accessible from your web application's front-end.
17
+ #
18
+ # For every request, it normally passes control to the {Assets} middleware,
19
+ # which injects needed JavaScript, CSS and HTML code for the console to work
20
+ # properly.
21
+ #
22
+ # It also exposes a special route used by the {Repl}, a Ruby evaluator which
23
+ # is responsible of keeping state between requests, remembering local
24
+ # variables and giving a true IRB-esque experience.
25
+ #
26
+ class Webconsole
27
+ # Honor the Rack contract by saving the passed Rack application in an ivar.
28
+ #
29
+ # @param [Rack::Application] app the previous Rack application in the
30
+ # middleware chain.
31
+ def initialize(app)
32
+ @app = app
33
+ end
34
+
35
+ # Decides where to send the request. In case the path is `/webconsole`
36
+ # (e.g. when calling the {Repl} endpoint), pass the request onto the
37
+ # {Repl}. Otherwise, pass it onto the {Assets} middleware, which will
38
+ # inject the needed assets for the Webconsole to work.
39
+ #
40
+ # @param [Hash] env a Rack request environment.
41
+ def call(env)
42
+ if env['PATH_INFO'] == '/webconsole'
43
+ Repl.new(@app).call(env)
44
+ else
45
+ Assets.new(@app).call(env)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ # encoding: utf-8
2
+ require 'rack'
3
+ require 'rack/webconsole'
@@ -0,0 +1,47 @@
1
+ body {
2
+ margin:0;
3
+ padding:0;
4
+ }
5
+ #console {
6
+ opacity: 0.9;
7
+ z-index: 999;
8
+ background: #000;
9
+ color: #DDD;
10
+ font-family: monospace;
11
+ padding-left: 15px;
12
+ padding-top: 10px;
13
+ height: 25%;
14
+ position: fixed;
15
+ width: 100%;
16
+ bottom: 0px;
17
+ border-top: 3px solid #DEDEDE;
18
+ overflow: hidden;
19
+ padding-top: 10px;
20
+ }
21
+ #console form div, #console form span {
22
+ font-size: 14px;
23
+ background: #000;
24
+ border: 0px;
25
+ font-family: monospace;
26
+ color: #FFF;
27
+ }
28
+ #console form div.results{
29
+ position: absolute;
30
+ bottom: 40px;
31
+ margin-bottom: -10px;
32
+ }
33
+ #console form div.input{
34
+ width: 97%;
35
+ position: absolute;
36
+ bottom: 10px;
37
+ }
38
+ #console form div.input input{
39
+ margin-top: 0px;
40
+ margin-bottom: 0px;
41
+ width: 97%;
42
+ font-size: 14px;
43
+ background: #000;
44
+ border: 0px;
45
+ font-family: monospace;
46
+ color: #FFF;
47
+ }
@@ -0,0 +1,12 @@
1
+ <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
2
+ <div id="console">
3
+ <form accept-charset="UTF-8" action="/webconsole" method="post">
4
+ <input name="utf8" type="hidden" value="✓"/>
5
+ <div class="results">
6
+ </div>
7
+ <div class="input">
8
+ <span>>></span>
9
+ <input id="query" name="query" type="text" />
10
+ </div>
11
+ </form>
12
+ </div>
@@ -0,0 +1,45 @@
1
+ $(document).ready(function() {
2
+ $("#console").hide();
3
+ $(this).keypress(function(event) {
4
+ if (event.which == 96) {
5
+ $("#console").slideToggle('fast', function() {
6
+ if ($(this).is(':visible')) {
7
+ $("#console form input").focus();
8
+ } else {
9
+ $("#console form input").blur();
10
+ }
11
+ });
12
+ event.preventDefault();
13
+ }
14
+ });
15
+ });
16
+ $('#console form').submit(function(e){
17
+ e.preventDefault();
18
+ });
19
+ String.prototype.escapeHTML = function () {
20
+ return(
21
+ this.replace(/&/g,'&amp;').
22
+ replace(/>/g,'&gt;').
23
+ replace(/</g,'&lt;').
24
+ replace(/"/g,'&quot;')
25
+ );
26
+ };
27
+
28
+ $("#console form input").keyup(function(event) {
29
+ if(event.which == 13) {
30
+ /*$.post('/webconsole', $("#console form").serialize());*/
31
+ var query = $("#query").val();
32
+ $.ajax({
33
+ url: '/webconsole',
34
+ type: 'POST',
35
+ dataType: 'json',
36
+ data: ({query: query}),
37
+ success: function (data) {
38
+ var q = "<div>>> " + query.escapeHTML() + "</div>";
39
+ var r = "<div>=> " + data.result.escapeHTML() + "</div>";
40
+ $("#console .results").append(q + r);
41
+ $("#query").val('');
42
+ }
43
+ });
44
+ }
45
+ });
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rack/webconsole/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rack-webconsole"
7
+ s.version = Rack::Webconsole::VERSION
8
+ s.authors = ["Josep M. Bach", "Josep Jaume Rey", "Oriol Gual"]
9
+ s.email = ["info@codegram.com"]
10
+ s.homepage = "http://github.com/codegram/rack-webconsole"
11
+ s.summary = %q{Rack-based console inside your web applications}
12
+ s.description = %q{Rack-based console inside your web applications}
13
+
14
+ s.rubyforge_project = "rack-webconsole"
15
+
16
+ s.add_runtime_dependency 'rack'
17
+ s.add_runtime_dependency 'json'
18
+
19
+ s.add_development_dependency 'minitest'
20
+ s.add_development_dependency 'purdytest'
21
+ s.add_development_dependency 'mocha'
22
+ s.add_development_dependency 'yard'
23
+ s.add_development_dependency 'bluecloth'
24
+ s.add_development_dependency 'rake'
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
+ s.require_paths = ["lib"]
30
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ class AssetClass
4
+ include Rack::Webconsole::AssetHelpers
5
+ end
6
+
7
+ module Rack
8
+ describe Webconsole::AssetHelpers do
9
+
10
+ describe '#html_code' do
11
+ it 'loads the html code' do
12
+ asset_class = AssetClass.new
13
+ html = asset_class.html_code
14
+
15
+ html.must_match /console/
16
+ html.must_match /results/
17
+ html.must_match /form/
18
+ end
19
+ end
20
+
21
+ describe '#css_code' do
22
+ it 'loads the css code' do
23
+ asset_class = AssetClass.new
24
+ css = asset_class.css_code
25
+
26
+ css.must_match /<style/
27
+ css.must_match /text\/css/
28
+ css.must_match /#console/
29
+ end
30
+ end
31
+
32
+ describe '#js_code' do
33
+ it 'loads the js code' do
34
+ asset_class = AssetClass.new
35
+ js = asset_class.js_code
36
+
37
+ js.must_match /\$\("#console"\)/
38
+ js.must_match /escapeHTML/
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module Rack
5
+ describe Webconsole::Assets do
6
+
7
+ it 'initializes with an app' do
8
+ @app = stub
9
+ @assets = Webconsole::Assets.new(@app)
10
+
11
+ @assets.instance_variable_get(:@app).must_equal @app
12
+ end
13
+
14
+ describe "#call" do
15
+
16
+ describe 'when the call is not appropriate to inject the view code' do
17
+ # Different invalid cases
18
+ [
19
+ [200, {'Content-Type' => 'text/html'}, ['Whatever']],
20
+ [200, {'Content-Type' => 'text/plain'}, ['Hello World']],
21
+ [404, {'Content-Type' => 'text/html'}, ['Hello World']],
22
+ [404, {'Content-Type' => 'text/html'}, ['Hello, World']],
23
+
24
+ ].each do |invalid_response|
25
+ it 'passes the call untouched' do
26
+ @app = lambda { |env| invalid_response }
27
+
28
+ assets = Webconsole::Assets.new(@app)
29
+ assets.expects(:inject_code).never
30
+
31
+ assets.call({}).last.first.must_equal invalid_response.last.first
32
+ end
33
+ end
34
+ end
35
+
36
+ describe 'otherwise' do
37
+
38
+ it 'injects the view code before the body ending' do
39
+
40
+ valid_html = "<!DOCTYPE html>\n<html>\n<head>\n <title>Testapp</title>\n <link href=\"/assets/application.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n <script src=\"/assets/application.js\" type=\"text/javascript\"></script>\n <meta content=\"authenticity_token\" name=\"csrf-param\" />\n<meta content=\"26Ls63zdKBiCXoqU5CuG6KqVbeMYydRqOuovP+DXx8g=\" name=\"csrf-token\" />\n</head>\n<body>\n\n<h1> Hello bitches </h1>\n\n<p> Lorem ipsum dolor sit amet. </p>\n\n\n</body>\n</html>\n"
41
+
42
+ html = [valid_html]
43
+
44
+ @app = lambda { |env| [200, {'Content-Type' => 'text/html'}, html] }
45
+
46
+ assets = Webconsole::Assets.new(@app)
47
+ response = assets.call({}).last.first
48
+
49
+ response.must_match /input name/m # html
50
+ response.must_match /text\/css/m # css
51
+ response.must_match /escapeHTML/m # js
52
+ end
53
+
54
+ it "works with Rails' particular conception of what a response is" do
55
+
56
+ valid_html = "<!DOCTYPE html>\n<html>\n<head>\n <title>Testapp</title>\n <link href=\"/assets/application.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n <script src=\"/assets/application.js\" type=\"text/javascript\"></script>\n <meta content=\"authenticity_token\" name=\"csrf-param\" />\n<meta content=\"26Ls63zdKBiCXoqU5CuG6KqVbeMYydRqOuovP+DXx8g=\" name=\"csrf-token\" />\n</head>\n<body>\n\n<h1> Hello bitches </h1>\n\n<p> Lorem ipsum dolor sit amet. </p>\n\n\n</body>\n</html>\n"
57
+
58
+ @app = lambda { |env| [200, {'Content-Type' => 'text/html'}, OpenStruct.new({:body => valid_html})] }
59
+
60
+ assets = Webconsole::Assets.new(@app)
61
+
62
+ response = assets.call({}).last.first
63
+
64
+ response.must_match /input name/m # html
65
+ response.must_match /text\/css/m # css
66
+ response.must_match /escapeHTML/m # js
67
+ end
68
+
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module Rack
5
+ describe Webconsole::Repl do
6
+
7
+ it 'initializes with an app' do
8
+ @app = stub
9
+ @repl = Webconsole::Repl.new(@app)
10
+
11
+ @repl.instance_variable_get(:@app).must_equal @app
12
+ end
13
+
14
+ describe "#call" do
15
+ it 'evaluates the :query param in a sandbox and returns the result' do
16
+ @app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello world']] }
17
+ env = {}
18
+ request = OpenStruct.new(:params => {'query' => 'a = 4; a * 2'})
19
+ Rack::Request.stubs(:new).returns request
20
+
21
+ @repl = Webconsole::Repl.new(@app)
22
+
23
+ response = @repl.call(env).last.first
24
+
25
+ JSON.parse(response)['result'].must_equal "8"
26
+ end
27
+
28
+ it 'maintains local state in subsequent calls thanks to an evil global variable' do
29
+ @app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello world']] }
30
+ env = {}
31
+ request = OpenStruct.new(:params => {'query' => 'a = 4'})
32
+ Rack::Request.stubs(:new).returns request
33
+ @repl = Webconsole::Repl.new(@app)
34
+
35
+ @repl.call(env) # call 1 sets a to 4
36
+
37
+ request = OpenStruct.new(:params => {'query' => 'a * 8'})
38
+ Rack::Request.stubs(:new).returns request
39
+
40
+ response = @repl.call(env).last.first # call 2 retrieves a and multiplies it by 8
41
+
42
+ JSON.parse(response)['result'].must_equal "32"
43
+ $sandbox.instance_variable_get(:@locals)[:a].must_equal 4
44
+ end
45
+
46
+ it "returns any found errors prepended with 'Error:'" do
47
+ @app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello world']] }
48
+ env = {}
49
+ request = OpenStruct.new(:params => {'query' => 'unknown_method'})
50
+ Rack::Request.stubs(:new).returns request
51
+ @repl = Webconsole::Repl.new(@app)
52
+
53
+ response = @repl.call(env).last.first
54
+
55
+ JSON.parse(response)['result'].must_match /Error:/
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module Rack
4
+ describe Webconsole::Sandbox do
5
+
6
+ describe "#method_missing" do
7
+ describe 'when the method exists in @locals' do
8
+ it 'retrieves it' do
9
+ @sandbox = Webconsole::Sandbox.new
10
+ @sandbox.instance_variable_set(:@locals, {:a => 123})
11
+
12
+ @sandbox.a.must_equal 123
13
+ end
14
+ end
15
+ describe 'otherwise' do
16
+ it 'raises a NoMethodError' do
17
+ @sandbox = Webconsole::Sandbox.new
18
+
19
+ lambda {
20
+ @sandbox.a
21
+ }.must_raise NoMethodError
22
+ end
23
+ end
24
+ end
25
+
26
+ describe "#reload!" do
27
+ it 'assigns a new, fresh Sandbox to the global variable' do
28
+ old_sandbox = $sandbox = Webconsole::Sandbox.new
29
+
30
+ $sandbox.reload!
31
+
32
+ $sandbox.wont_equal old_sandbox
33
+ end
34
+ it 'returns a feedback string' do
35
+ Webconsole::Sandbox.new.reload!.must_equal 'ok'
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module Rack
4
+ describe Webconsole do
5
+
6
+ it 'initializes with an app' do
7
+ @app = stub
8
+ @webconsole = Webconsole.new(@app)
9
+
10
+ @webconsole.instance_variable_get(:@app).must_equal @app
11
+ end
12
+
13
+ describe "#call" do
14
+ it 'delegates the call to the Repl middleware when the path is /webconsole' do
15
+ @app = stub
16
+ @webconsole = Webconsole.new(@app)
17
+ @env = {'PATH_INFO' => '/webconsole'}
18
+
19
+ repl = stub
20
+ Webconsole::Repl.expects(:new).with(@app).returns repl
21
+ repl.expects(:call).with @env
22
+
23
+ @webconsole.call(@env)
24
+ end
25
+
26
+ it 'passes the call to the Assets middleware otherwise' do
27
+ @app = stub
28
+ @webconsole = Webconsole.new(@app)
29
+ @env = {'PATH_INFO' => '/whatever'}
30
+
31
+ assets = stub
32
+ Webconsole::Assets.expects(:new).with(@app).returns assets
33
+ assets.expects(:call).with @env
34
+
35
+ @webconsole.call(@env)
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,8 @@
1
+ gem 'minitest'
2
+ require 'minitest/spec'
3
+ require 'minitest/autorun'
4
+ require 'purdytest'
5
+ require 'mocha'
6
+
7
+ require 'rack-webconsole'
8
+
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-webconsole
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Josep M. Bach
9
+ - Josep Jaume Rey
10
+ - Oriol Gual
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+
15
+ date: 2011-07-24 00:00:00 +02:00
16
+ default_executable:
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: rack
20
+ prerelease: false
21
+ requirement: &id001 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: "0"
27
+ type: :runtime
28
+ version_requirements: *id001
29
+ - !ruby/object:Gem::Dependency
30
+ name: json
31
+ prerelease: false
32
+ requirement: &id002 !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: "0"
38
+ type: :runtime
39
+ version_requirements: *id002
40
+ - !ruby/object:Gem::Dependency
41
+ name: minitest
42
+ prerelease: false
43
+ requirement: &id003 !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id003
51
+ - !ruby/object:Gem::Dependency
52
+ name: purdytest
53
+ prerelease: false
54
+ requirement: &id004 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id004
62
+ - !ruby/object:Gem::Dependency
63
+ name: mocha
64
+ prerelease: false
65
+ requirement: &id005 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ type: :development
72
+ version_requirements: *id005
73
+ - !ruby/object:Gem::Dependency
74
+ name: yard
75
+ prerelease: false
76
+ requirement: &id006 !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: "0"
82
+ type: :development
83
+ version_requirements: *id006
84
+ - !ruby/object:Gem::Dependency
85
+ name: bluecloth
86
+ prerelease: false
87
+ requirement: &id007 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: "0"
93
+ type: :development
94
+ version_requirements: *id007
95
+ - !ruby/object:Gem::Dependency
96
+ name: rake
97
+ prerelease: false
98
+ requirement: &id008 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: "0"
104
+ type: :development
105
+ version_requirements: *id008
106
+ description: Rack-based console inside your web applications
107
+ email:
108
+ - info@codegram.com
109
+ executables: []
110
+
111
+ extensions: []
112
+
113
+ extra_rdoc_files: []
114
+
115
+ files:
116
+ - .gitignore
117
+ - .rvmrc
118
+ - Gemfile
119
+ - Gemfile.lock
120
+ - Rakefile
121
+ - Readme.md
122
+ - lib/rack-webconsole.rb
123
+ - lib/rack/webconsole.rb
124
+ - lib/rack/webconsole/asset_helpers.rb
125
+ - lib/rack/webconsole/assets.rb
126
+ - lib/rack/webconsole/railtie.rb
127
+ - lib/rack/webconsole/repl.rb
128
+ - lib/rack/webconsole/sandbox.rb
129
+ - lib/rack/webconsole/version.rb
130
+ - public/webconsole.css
131
+ - public/webconsole.html
132
+ - public/webconsole.js
133
+ - rack-webconsole.gemspec
134
+ - spec/rack/webconsole/asset_helpers_spec.rb
135
+ - spec/rack/webconsole/assets_spec.rb
136
+ - spec/rack/webconsole/repl_spec.rb
137
+ - spec/rack/webconsole/sandbox_spec.rb
138
+ - spec/rack/webconsole_spec.rb
139
+ - spec/spec_helper.rb
140
+ has_rdoc: true
141
+ homepage: http://github.com/codegram/rack-webconsole
142
+ licenses: []
143
+
144
+ post_install_message:
145
+ rdoc_options: []
146
+
147
+ require_paths:
148
+ - lib
149
+ required_ruby_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: "0"
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: "0"
161
+ requirements: []
162
+
163
+ rubyforge_project: rack-webconsole
164
+ rubygems_version: 1.6.1
165
+ signing_key:
166
+ specification_version: 3
167
+ summary: Rack-based console inside your web applications
168
+ test_files:
169
+ - spec/rack/webconsole/asset_helpers_spec.rb
170
+ - spec/rack/webconsole/assets_spec.rb
171
+ - spec/rack/webconsole/repl_spec.rb
172
+ - spec/rack/webconsole/sandbox_spec.rb
173
+ - spec/rack/webconsole_spec.rb
174
+ - spec/spec_helper.rb