cans 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/README.rdoc +5 -4
- data/Rakefile +16 -28
- data/cans.gemspec +14 -66
- data/config/evergreen.rb +3 -0
- data/lib/cans/application.rb +49 -1
- data/lib/cans/static/application.js +253 -0
- data/lib/cans/static/backbone-min.js +26 -0
- data/lib/cans/static/frameset.css +42 -0
- data/lib/cans/static/jquery-1.4.4.min.js +167 -0
- data/lib/cans/static/json2.js +483 -0
- data/lib/cans/static/shBrushRuby.js +55 -0
- data/lib/cans/static/shCore.js +17 -0
- data/lib/cans/static/shCoreMidnight.css +324 -0
- data/lib/cans/static/underscore-min.js +26 -0
- data/lib/cans/version.rb +3 -0
- data/lib/cans/views/application.coffee +161 -0
- data/lib/cans/views/frameset.haml +38 -0
- data/lib/cans.rb +1 -1
- data/spec/javascripts/instance_method_spec.coffee +21 -0
- data/spec/javascripts/machine_spec.coffee +31 -0
- data/spec/javascripts/machine_view_spec.coffee +3 -0
- data/spec/javascripts/method_spec.coffee +21 -0
- data/spec/javascripts/module_spec.coffee +44 -0
- data/spec/javascripts/spec_helper.js +10 -0
- data/spec/javascripts/support/jasmine.yml +73 -0
- data/spec/javascripts/support/jasmine_runner.rb +32 -0
- data/spec/javascripts/templates/view_templates.html +8 -0
- data/tmp/.gitignore +3 -0
- metadata +75 -15
- data/Gemfile.lock +0 -38
- data/VERSION +0 -1
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -2,9 +2,6 @@
|
|
2
2
|
|
3
3
|
Interactive online source browser for Rack applications.
|
4
4
|
|
5
|
-
Experimental and unfinished. This gem will probably kill
|
6
|
-
you in your sleep if you try to use it right now.
|
7
|
-
|
8
5
|
== Using in Rails 3
|
9
6
|
|
10
7
|
Add "cans" to your Gemfile:
|
@@ -19,6 +16,10 @@ Start your Rails app, and use it a bit. Understand that cans will add an after_
|
|
19
16
|
|
20
17
|
Then, visit the cans mountpoint and browse around.
|
21
18
|
|
19
|
+
== Testing
|
20
|
+
|
21
|
+
Unit tests are in the "test/unit" directory, using "shoulda" from ThoughtBot. Run them with "rake test".
|
22
|
+
|
22
23
|
== Note on Patches/Pull Requests
|
23
24
|
|
24
25
|
* Fork the project.
|
@@ -31,4 +32,4 @@ Then, visit the cans mountpoint and browse around.
|
|
31
32
|
|
32
33
|
== Copyright
|
33
34
|
|
34
|
-
Copyright (c) 2010 Bryce Kerley. See LICENSE for details.
|
35
|
+
Copyright (c) 2010-2011 Bryce Kerley. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,32 +1,13 @@
|
|
1
|
-
require '
|
2
|
-
require 'rake'
|
3
|
-
|
1
|
+
require 'bundler'
|
4
2
|
begin
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
gem.homepage = "http://github.com/bkerley/cans"
|
12
|
-
gem.authors = ["Bryce Kerley"]
|
13
|
-
|
14
|
-
gem.add_dependency 'sinatra', '~> 1.1.0'
|
15
|
-
gem.add_dependency 'haml', '~> 3.0.22'
|
16
|
-
gem.add_dependency 'method_extensions', '~> 0.0.8'
|
17
|
-
|
18
|
-
gem.add_development_dependency "shoulda", "~> 2.11.3"
|
19
|
-
gem.add_development_dependency 'rack-test', '~> 0.5.6'
|
20
|
-
gem.add_development_dependency 'mocha', '~> 0.9.9'
|
21
|
-
|
22
|
-
gem.required_ruby_version = '~> 1.9.2'
|
23
|
-
|
24
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
25
|
-
end
|
26
|
-
Jeweler::GemcutterTasks.new
|
27
|
-
rescue LoadError
|
28
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
29
9
|
end
|
10
|
+
require 'rake'
|
30
11
|
|
31
12
|
require 'rake/testtask'
|
32
13
|
Rake::TestTask.new(:test) do |test|
|
@@ -48,7 +29,7 @@ rescue LoadError
|
|
48
29
|
end
|
49
30
|
end
|
50
31
|
|
51
|
-
task :test
|
32
|
+
task :test
|
52
33
|
|
53
34
|
task :default => :test
|
54
35
|
|
@@ -61,3 +42,10 @@ Rake::RDocTask.new do |rdoc|
|
|
61
42
|
rdoc.rdoc_files.include('README*')
|
62
43
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
63
44
|
end
|
45
|
+
|
46
|
+
desc 'Compile the coffeescript files to javascript'
|
47
|
+
task :coffeescript => 'lib/cans/static/application.js'
|
48
|
+
|
49
|
+
file 'lib/cans/static/application.js' => 'lib/cans/views/application.coffee' do
|
50
|
+
system 'coffee -co lib/cans/static lib/cans/views/application.coffee'
|
51
|
+
end
|
data/cans.gemspec
CHANGED
@@ -1,87 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
-
# -*- encoding: utf-8 -*-
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require 'cans/version'
|
5
3
|
|
6
4
|
Gem::Specification.new do |s|
|
7
5
|
s.name = %q{cans}
|
8
|
-
s.version =
|
6
|
+
s.version = Cans::VERSION
|
9
7
|
|
10
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
9
|
s.authors = ["Bryce Kerley"]
|
12
|
-
s.date = %q{
|
10
|
+
s.date = %q{2011-05-19}
|
13
11
|
s.description = %q{Interactive on-line source browser for rack applications}
|
14
12
|
s.email = %q{bkerley@brycekerley.net}
|
15
13
|
s.extra_rdoc_files = [
|
16
14
|
"LICENSE",
|
17
15
|
"README.rdoc"
|
18
16
|
]
|
19
|
-
s.files =
|
20
|
-
|
21
|
-
".gitignore",
|
22
|
-
"Gemfile",
|
23
|
-
"Gemfile.lock",
|
24
|
-
"LICENSE",
|
25
|
-
"README.rdoc",
|
26
|
-
"Rakefile",
|
27
|
-
"VERSION",
|
28
|
-
"cans.gemspec",
|
29
|
-
"config.ru",
|
30
|
-
"lib/cans.rb",
|
31
|
-
"lib/cans/address.rb",
|
32
|
-
"lib/cans/application.rb",
|
33
|
-
"lib/cans/historian.rb",
|
34
|
-
"lib/cans/views/index.haml",
|
35
|
-
"lib/cans/views/method.haml",
|
36
|
-
"lib/cans/views/module.haml",
|
37
|
-
"test/fixtures/beverage.rb",
|
38
|
-
"test/helper.rb",
|
39
|
-
"test/test_address.rb",
|
40
|
-
"test/test_application.rb",
|
41
|
-
"test/test_cans.rb",
|
42
|
-
"test/test_historian.rb"
|
43
|
-
]
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
44
19
|
s.homepage = %q{http://github.com/bkerley/cans}
|
45
20
|
s.rdoc_options = ["--charset=UTF-8"]
|
46
21
|
s.require_paths = ["lib"]
|
47
22
|
s.required_ruby_version = Gem::Requirement.new("~> 1.9.2")
|
48
23
|
s.rubygems_version = %q{1.3.7}
|
49
24
|
s.summary = %q{Source browser for Rack applications}
|
50
|
-
s.test_files = [
|
51
|
-
"test/fixtures/beverage.rb",
|
52
|
-
"test/helper.rb",
|
53
|
-
"test/test_address.rb",
|
54
|
-
"test/test_application.rb",
|
55
|
-
"test/test_cans.rb",
|
56
|
-
"test/test_historian.rb"
|
57
|
-
]
|
58
|
-
|
59
|
-
if s.respond_to? :specification_version then
|
60
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
61
|
-
s.specification_version = 3
|
62
25
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
|
72
|
-
s.add_dependency(%q<haml>, ["~> 3.0.22"])
|
73
|
-
s.add_dependency(%q<method_extensions>, ["~> 0.0.8"])
|
74
|
-
s.add_dependency(%q<shoulda>, ["~> 2.11.3"])
|
75
|
-
s.add_dependency(%q<rack-test>, ["~> 0.5.6"])
|
76
|
-
s.add_dependency(%q<mocha>, ["~> 0.9.9"])
|
77
|
-
end
|
78
|
-
else
|
79
|
-
s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
|
80
|
-
s.add_dependency(%q<haml>, ["~> 3.0.22"])
|
81
|
-
s.add_dependency(%q<method_extensions>, ["~> 0.0.8"])
|
82
|
-
s.add_dependency(%q<shoulda>, ["~> 2.11.3"])
|
83
|
-
s.add_dependency(%q<rack-test>, ["~> 0.5.6"])
|
84
|
-
s.add_dependency(%q<mocha>, ["~> 0.9.9"])
|
85
|
-
end
|
26
|
+
s.add_runtime_dependency(%q<sinatra>, ["~> 1.1.0"])
|
27
|
+
s.add_runtime_dependency(%q<haml>, ["~> 3.0.22"])
|
28
|
+
s.add_runtime_dependency(%q<method_extensions>, ["~> 0.0.8"])
|
29
|
+
s.add_development_dependency(%q<shoulda>, ["~> 2.11.3"])
|
30
|
+
s.add_development_dependency(%q<rack-test>, ["~> 0.5.6"])
|
31
|
+
s.add_development_dependency(%q<coffee-script>, ["~> 1.1.0"])
|
32
|
+
s.add_development_dependency(%q<evergreen>, ["~> 0.4.0"])
|
33
|
+
s.add_development_dependency(%q<mocha>, ["~> 0.9.12"])
|
86
34
|
end
|
87
35
|
|
data/config/evergreen.rb
ADDED
data/lib/cans/application.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Cans
|
2
2
|
class Application < Sinatra::Base
|
3
3
|
set :views, File.dirname(__FILE__) + '/views'
|
4
|
+
set :public, File.dirname(__FILE__) + '/static'
|
4
5
|
|
5
6
|
get '/' do
|
6
7
|
@constants = Object.constants
|
@@ -9,6 +10,49 @@ module Cans
|
|
9
10
|
haml :index
|
10
11
|
end
|
11
12
|
|
13
|
+
get '/browser' do
|
14
|
+
haml :frameset
|
15
|
+
end
|
16
|
+
|
17
|
+
post '/browser/image' do
|
18
|
+
@constants = Object.constants
|
19
|
+
@modules = @constants.map{ |c| Object.const_get c}.select{ |c| c.kind_of? Module}.map(&:name).sort
|
20
|
+
content_type :json
|
21
|
+
to_json({ :modules=>@modules })
|
22
|
+
end
|
23
|
+
|
24
|
+
post '/browser/class/*' do
|
25
|
+
@address = Address.new(params[:splat].first)
|
26
|
+
@module = @address.target_module
|
27
|
+
|
28
|
+
@local_instance_methods = @module.instance_methods false
|
29
|
+
@all_instance_methods = @module.instance_methods true
|
30
|
+
@super_instance_methods = @all_instance_methods - @local_instance_methods
|
31
|
+
|
32
|
+
@class_methods = @module.methods.map(&:to_s).sort
|
33
|
+
|
34
|
+
@ancestors = @module.ancestors
|
35
|
+
@child_modules = @module.constants.map{ |c| @module.const_get c}.select{ |c| c.kind_of? Module}.map(&:name).sort
|
36
|
+
|
37
|
+
content_type :json
|
38
|
+
to_json({ :child_modules=>@child_modules,
|
39
|
+
:class_methods=>@class_methods,
|
40
|
+
:local_instance_methods=>@local_instance_methods.map(&:to_s).sort,
|
41
|
+
:inherited_instance_methods=>@super_instance_methods.map(&:to_s).sort
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
post '/browser/method/*' do
|
46
|
+
@address = Address.new(params[:splat].first)
|
47
|
+
@module = @address.target_module
|
48
|
+
@method = @address.target_method
|
49
|
+
|
50
|
+
@source = @method.source_with_doc
|
51
|
+
@location = @method.source_location
|
52
|
+
|
53
|
+
to_json({ :source=>@source, :source_location=>@location })
|
54
|
+
end
|
55
|
+
|
12
56
|
get '/module/*' do
|
13
57
|
@address = Address.new(params[:splat].first)
|
14
58
|
@module = @address.target_module
|
@@ -19,7 +63,7 @@ module Cans
|
|
19
63
|
|
20
64
|
@class_methods = @module.methods
|
21
65
|
|
22
|
-
@ancestors = @module.ancestors
|
66
|
+
@ancestors = @module.ancestors.sort_by(&:name)
|
23
67
|
@child_modules = @module.constants.map{ |c| @module.const_get c}.select{ |c| c.kind_of? Module}.sort_by(&:name)
|
24
68
|
|
25
69
|
haml :module
|
@@ -47,6 +91,10 @@ module Cans
|
|
47
91
|
href = prefix + destination
|
48
92
|
"<a href='#{href}'>#{content}</a>"
|
49
93
|
end
|
94
|
+
|
95
|
+
def to_json(hash)
|
96
|
+
JSON.generate hash
|
97
|
+
end
|
50
98
|
end
|
51
99
|
end
|
52
100
|
end
|
@@ -0,0 +1,253 @@
|
|
1
|
+
(function() {
|
2
|
+
var __bind = function(func, context) {
|
3
|
+
return function(){ return func.apply(context, arguments); };
|
4
|
+
}, __extends = function(child, parent) {
|
5
|
+
var ctor = function(){};
|
6
|
+
ctor.prototype = parent.prototype;
|
7
|
+
child.prototype = new ctor();
|
8
|
+
child.prototype.constructor = child;
|
9
|
+
if (typeof parent.extended === "function") parent.extended(child);
|
10
|
+
child.__super__ = parent.prototype;
|
11
|
+
};
|
12
|
+
jQuery(function() {
|
13
|
+
var Ajax;
|
14
|
+
jQuery.ajaxSetup({
|
15
|
+
type: 'post',
|
16
|
+
dataType: 'json'
|
17
|
+
});
|
18
|
+
Ajax = function(path, callback) {
|
19
|
+
var fullPath;
|
20
|
+
fullPath = window.location.pathname + path;
|
21
|
+
return jQuery.ajax({
|
22
|
+
url: fullPath,
|
23
|
+
success: callback
|
24
|
+
});
|
25
|
+
};
|
26
|
+
window.Machine = function() {
|
27
|
+
this.load();
|
28
|
+
return this;
|
29
|
+
};
|
30
|
+
window.Machine.prototype.load = function() {
|
31
|
+
return Ajax('/image', __bind(function(data) {
|
32
|
+
return this.consume(data);
|
33
|
+
}, this));
|
34
|
+
};
|
35
|
+
window.Machine.prototype.consume = function(returned) {
|
36
|
+
this.modules = _.map(returned.modules, function(m) {
|
37
|
+
return new Module(m);
|
38
|
+
});
|
39
|
+
return this.view.trigger('loaded');
|
40
|
+
};
|
41
|
+
window.Module = function(_arg) {
|
42
|
+
this.name = _arg;
|
43
|
+
this.view = null;
|
44
|
+
return this;
|
45
|
+
};
|
46
|
+
window.Module.prototype.load = function() {
|
47
|
+
return Ajax("/class/" + (this.name), __bind(function(data) {
|
48
|
+
return this.consume(data);
|
49
|
+
}, this));
|
50
|
+
};
|
51
|
+
window.Module.prototype.consume = function(returned) {
|
52
|
+
this.childModules = _.map(returned.child_modules, __bind(function(m) {
|
53
|
+
return new Module(m);
|
54
|
+
}, this));
|
55
|
+
this.classMethods = _.map(returned.class_methods, __bind(function(m) {
|
56
|
+
return new ClassMethod(this, m);
|
57
|
+
}, this));
|
58
|
+
this.localInstanceMethods = _.map(returned.local_instance_methods, __bind(function(m) {
|
59
|
+
return new InstanceMethod(this, m);
|
60
|
+
}, this));
|
61
|
+
this.inheritedInstanceMethods = _.map(returned.inherited_instance_methods, __bind(function(m) {
|
62
|
+
return new InstanceMethod(this, m);
|
63
|
+
}, this));
|
64
|
+
return this.view.trigger('loaded');
|
65
|
+
};
|
66
|
+
window.Module.prototype.toJSON = function() {
|
67
|
+
return {
|
68
|
+
name: this.name
|
69
|
+
};
|
70
|
+
};
|
71
|
+
window.Method = function(_arg, _arg2) {
|
72
|
+
this.name = _arg2;
|
73
|
+
this.module = _arg;
|
74
|
+
return this;
|
75
|
+
};
|
76
|
+
window.Method.prototype.load = function(flavor) {
|
77
|
+
return Ajax(this.url(), __bind(function(data) {
|
78
|
+
return this.consume(data);
|
79
|
+
}, this));
|
80
|
+
};
|
81
|
+
window.Method.prototype.consume = function(returned) {
|
82
|
+
this.source = returned.source;
|
83
|
+
if (this.source) {
|
84
|
+
this.source_file = returned.source_location[0];
|
85
|
+
this.source_line = returned.source_location[1];
|
86
|
+
}
|
87
|
+
return this.view.trigger('loaded');
|
88
|
+
};
|
89
|
+
window.Method.prototype.url = function() {
|
90
|
+
return "/method/" + (escape(this.module.name)) + "/." + (escape(this.flavor)) + "/" + (escape(this.name));
|
91
|
+
};
|
92
|
+
window.Method.prototype.toJSON = function() {
|
93
|
+
return {
|
94
|
+
module: this.module.toJSON(),
|
95
|
+
name: this.name,
|
96
|
+
source: this.source,
|
97
|
+
file: this.source_file,
|
98
|
+
line: this.source_line,
|
99
|
+
flavor: this.flavor,
|
100
|
+
flavorSymbol: this.flavorSymbol
|
101
|
+
};
|
102
|
+
};
|
103
|
+
window.InstanceMethod = function() {
|
104
|
+
return window.Method.apply(this, arguments);
|
105
|
+
};
|
106
|
+
__extends(window.InstanceMethod, window.Method);
|
107
|
+
window.InstanceMethod.prototype.flavor = 'i';
|
108
|
+
window.InstanceMethod.prototype.flavorSymbol = '#';
|
109
|
+
window.ClassMethod = function() {
|
110
|
+
return window.Method.apply(this, arguments);
|
111
|
+
};
|
112
|
+
__extends(window.ClassMethod, window.Method);
|
113
|
+
window.ClassMethod.prototype.flavor = 'm';
|
114
|
+
window.ClassMethod.prototype.flavorSymbol = '::';
|
115
|
+
window.SourceView = Backbone.View.extend({
|
116
|
+
tagName: 'div',
|
117
|
+
template: _.template($('#source_template').html()),
|
118
|
+
errorTemplate: _.template($('#source_error_template').html()),
|
119
|
+
render: function() {
|
120
|
+
if (this.model.source) {
|
121
|
+
return this.renderOkay();
|
122
|
+
} else {
|
123
|
+
return this.renderError();
|
124
|
+
}
|
125
|
+
},
|
126
|
+
renderOkay: function() {
|
127
|
+
var rendered;
|
128
|
+
rendered = this.template(this.model.toJSON());
|
129
|
+
$(this.el).html(rendered);
|
130
|
+
return this;
|
131
|
+
},
|
132
|
+
renderError: function() {
|
133
|
+
var rendered;
|
134
|
+
rendered = this.errorTemplate(this.model.toJSON());
|
135
|
+
$(this.el).html(rendered);
|
136
|
+
return this;
|
137
|
+
}
|
138
|
+
});
|
139
|
+
window.MethodView = Backbone.View.extend({
|
140
|
+
tagName: 'li',
|
141
|
+
template: _.template($('#method_template').html()),
|
142
|
+
events: {
|
143
|
+
'click': 'loadSource'
|
144
|
+
},
|
145
|
+
initialize: function() {
|
146
|
+
this.model.view = this;
|
147
|
+
return this.bind('loaded', this.drawSource);
|
148
|
+
},
|
149
|
+
loadSource: function() {
|
150
|
+
$('#content').html('');
|
151
|
+
this.model.load();
|
152
|
+
return false;
|
153
|
+
},
|
154
|
+
drawSource: function() {
|
155
|
+
var sourceView;
|
156
|
+
sourceView = new SourceView({
|
157
|
+
model: this.model
|
158
|
+
});
|
159
|
+
$('#content').html(sourceView.render().el);
|
160
|
+
return SyntaxHighlighter.highlight({}, $('#content pre')[0]);
|
161
|
+
},
|
162
|
+
render: function() {
|
163
|
+
var rendered;
|
164
|
+
rendered = this.template(this.model.toJSON());
|
165
|
+
$(this.el).html(rendered);
|
166
|
+
$(this.el).addClass(this.model.flavor);
|
167
|
+
return this;
|
168
|
+
}
|
169
|
+
});
|
170
|
+
window.ModuleView = Backbone.View.extend({
|
171
|
+
tagName: 'li',
|
172
|
+
template: _.template($('#module_template').html()),
|
173
|
+
events: {
|
174
|
+
'click': 'loadChildren'
|
175
|
+
},
|
176
|
+
initialize: function() {
|
177
|
+
this.model.view = this;
|
178
|
+
return this.bind('loaded', this.drawChildren);
|
179
|
+
},
|
180
|
+
loadChildren: function() {
|
181
|
+
$('#class_method_list').html('');
|
182
|
+
$('#instance_method_list').html('');
|
183
|
+
$('#content').html('');
|
184
|
+
$(this.el).children('.child_modules').html('');
|
185
|
+
this.model.load();
|
186
|
+
return false;
|
187
|
+
},
|
188
|
+
drawChildren: function() {
|
189
|
+
this.drawChildModules();
|
190
|
+
this.drawClassMethods();
|
191
|
+
return this.drawInstanceMethods();
|
192
|
+
},
|
193
|
+
drawClassMethods: function() {
|
194
|
+
return _(this.model.classMethods).each(function(m) {
|
195
|
+
var view;
|
196
|
+
view = new MethodView({
|
197
|
+
model: m
|
198
|
+
});
|
199
|
+
return $('#class_method_list').append(view.render().el);
|
200
|
+
});
|
201
|
+
},
|
202
|
+
drawInstanceMethods: function() {
|
203
|
+
_(this.model.localInstanceMethods).each(function(m) {
|
204
|
+
var view;
|
205
|
+
view = new MethodView({
|
206
|
+
model: m
|
207
|
+
});
|
208
|
+
return $('#instance_method_list').append(view.render().el);
|
209
|
+
});
|
210
|
+
return _(this.model.inheritedInstanceMethods).each(function(m) {
|
211
|
+
var view;
|
212
|
+
view = new MethodView({
|
213
|
+
model: m
|
214
|
+
});
|
215
|
+
return $('#instance_method_list').append(view.render().el);
|
216
|
+
});
|
217
|
+
},
|
218
|
+
drawChildModules: function() {
|
219
|
+
return _(this.model.childModules).each(__bind(function(m) {
|
220
|
+
var view;
|
221
|
+
view = new ModuleView({
|
222
|
+
model: m
|
223
|
+
});
|
224
|
+
return $(this.el).children('.child_modules').append(view.render().el);
|
225
|
+
}, this));
|
226
|
+
},
|
227
|
+
render: function() {
|
228
|
+
var rendered;
|
229
|
+
rendered = this.template(this.model.toJSON());
|
230
|
+
$(this.el).html(rendered);
|
231
|
+
return this;
|
232
|
+
}
|
233
|
+
});
|
234
|
+
window.MachineView = Backbone.View.extend({
|
235
|
+
initialize: function() {
|
236
|
+
this.model.view = this;
|
237
|
+
return this.bind('loaded', this.drawModules);
|
238
|
+
},
|
239
|
+
drawModules: function() {
|
240
|
+
return _(this.model.modules).each(function(m) {
|
241
|
+
var view;
|
242
|
+
view = new ModuleView({
|
243
|
+
model: m
|
244
|
+
});
|
245
|
+
return $('#module_list').append(view.render().el);
|
246
|
+
});
|
247
|
+
}
|
248
|
+
});
|
249
|
+
return (window.App = new window.MachineView({
|
250
|
+
model: new window.Machine()
|
251
|
+
}));
|
252
|
+
});
|
253
|
+
}).call(this);
|
@@ -0,0 +1,26 @@
|
|
1
|
+
// Backbone.js 0.3.1
|
2
|
+
// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
|
3
|
+
// Backbone may be freely distributed under the MIT license.
|
4
|
+
// For all details and documentation:
|
5
|
+
// http://documentcloud.github.com/backbone
|
6
|
+
(function(){var e;e=typeof exports!=="undefined"?exports:this.Backbone={};e.VERSION="0.3.1";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var h=this.jQuery;e.emulateHTTP=false;e.emulateJSON=false;e.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=0,g=c.length;d<g;d++)if(b===c[d]){c.splice(d,1);
|
7
|
+
break}}else c[a]=[]}else this._callbacks={};return this},trigger:function(a){var b,c,d,g;if(!(c=this._callbacks))return this;if(b=c[a]){d=0;for(g=b.length;d<g;d++)b[d].apply(this,Array.prototype.slice.call(arguments,1))}if(b=c.all){d=0;for(g=b.length;d<g;d++)b[d].apply(this,arguments)}return this}};e.Model=function(a,b){this.attributes={};this.cid=f.uniqueId("c");this.set(a||{},{silent:true});this._previousAttributes=f.clone(this.attributes);if(b&&b.collection)this.collection=b.collection;this.initialize&&
|
8
|
+
this.initialize(a,b)};f.extend(e.Model.prototype,e.Events,{_previousAttributes:null,_changed:false,toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},set:function(a,b){b||(b={});if(!a)return this;if(a.attributes)a=a.attributes;var c=this.attributes;if(!b.silent&&this.validate&&!this._performValidation(a,b))return false;if("id"in a)this.id=a.id;for(var d in a){var g=a[d];if(!f.isEqual(c[d],g)){c[d]=g;if(!b.silent){this._changed=true;this.trigger("change:"+
|
9
|
+
d,this,g)}}}!b.silent&&this._changed&&this.change();return this},unset:function(a,b){b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&&!this._performValidation(c,b))return false;delete this.attributes[a];if(!b.silent){this._changed=true;this.trigger("change:"+a,this);this.change()}return this},clear:function(a){a||(a={});var b=this.attributes,c={};for(attr in b)c[attr]=void 0;if(!a.silent&&this.validate&&!this._performValidation(c,a))return false;this.attributes={};if(!a.silent){this._changed=
|
10
|
+
true;for(attr in b)this.trigger("change:"+attr,this);this.change()}return this},fetch:function(a){a||(a={});var b=this,c=a.error&&f.bind(a.error,null,b);e.sync("read",this,function(d){if(!b.set(b.parse(d),a))return false;a.success&&a.success(b,d)},c);return this},save:function(a,b){a||(a={});b||(b={});if(!this.set(a,b))return false;var c=this,d=b.error&&f.bind(b.error,null,c),g=this.isNew()?"create":"update";e.sync(g,this,function(i){if(!c.set(c.parse(i),b))return false;b.success&&b.success(c,i)},
|
11
|
+
d);return this},destroy:function(a){a||(a={});var b=this,c=a.error&&f.bind(a.error,null,b);e.sync("delete",this,function(d){b.collection&&b.collection.remove(b);a.success&&a.success(b,d)},c);return this},url:function(){var a=j(this.collection);if(this.isNew())return a;return a+"/"+this.id},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return!this.id},change:function(){this.trigger("change",this);this._previousAttributes=f.clone(this.attributes);this._changed=
|
12
|
+
false},hasChanged:function(a){if(a)return this._previousAttributes[a]!=this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=false,d;for(d in a)if(!f.isEqual(b[d],a[d])){c=c||{};c[d]=a[d]}return c},previous:function(a){if(!a||!this._previousAttributes)return null;return this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},_performValidation:function(a,b){var c=this.validate(a);
|
13
|
+
if(c){b.error?b.error(this,c):this.trigger("error",this,c);return false}return true}});e.Collection=function(a,b){b||(b={});if(b.comparator){this.comparator=b.comparator;delete b.comparator}this._boundOnModelEvent=f.bind(this._onModelEvent,this);this._reset();a&&this.refresh(a,{silent:true});this.initialize&&this.initialize(a,b)};f.extend(e.Collection.prototype,e.Events,{model:e.Model,toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){if(f.isArray(a))for(var c=0,
|
14
|
+
d=a.length;c<d;c++)this._add(a[c],b);else this._add(a,b);return this},remove:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c<d;c++)this._remove(a[c],b);else this._remove(a,b);return this},get:function(a){return a&&this._byId[a.id!=null?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");this.models=this.sortBy(this.comparator);a.silent||this.trigger("refresh",
|
15
|
+
this);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},refresh:function(a,b){a||(a=[]);b||(b={});this._reset();this.add(a,{silent:true});b.silent||this.trigger("refresh",this);return this},fetch:function(a){a||(a={});var b=this,c=a.error&&f.bind(a.error,null,b);e.sync("read",this,function(d){b.refresh(b.parse(d));a.success&&a.success(b,d)},c);return this},create:function(a,b){var c=this;b||(b={});if(a instanceof e.Model)a.collection=c;else a=new this.model(a,
|
16
|
+
{collection:c});return a.save(null,{success:function(d,g){c.add(d);b.success&&b.success(d,g)},error:b.error})},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId={};this._byCid={}},_add:function(a,b){b||(b={});a instanceof e.Model||(a=new this.model(a,{collection:this}));var c=this.getByCid(a);if(c)throw Error(["Can't add the same model to a set twice",c.id]);this._byId[a.id]=a;this._byCid[a.cid]=a;a.collection=this;
|
17
|
+
this.models.splice(this.comparator?this.sortedIndex(a,this.comparator):this.length,0,a);a.bind("all",this._boundOnModelEvent);this.length++;b.silent||a.trigger("add",a,this);return a},_remove:function(a,b){b||(b={});a=this.getByCid(a);if(!a)return null;delete this._byId[a.id];delete this._byCid[a.cid];delete a.collection;this.models.splice(this.indexOf(a),1);this.length--;b.silent||a.trigger("remove",a,this);a.unbind("all",this._boundOnModelEvent);return a},_onModelEvent:function(a,b){if(a==="change:id"){delete this._byId[b.previous("id")];
|
18
|
+
this._byId[b.id]=b}this.trigger.apply(this,arguments)}});f.each(["forEach","each","map","reduce","reduceRight","find","detect","filter","select","reject","every","all","some","any","include","invoke","max","min","sortBy","sortedIndex","toArray","size","first","rest","last","without","indexOf","lastIndexOf","isEmpty"],function(a){e.Collection.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});e.Controller=function(a){a||(a={});if(a.routes)this.routes=a.routes;
|
19
|
+
this._bindRoutes();this.initialize&&this.initialize(a)};var o=/:([\w\d]+)/g,p=/\*([\w\d]+)/g;f.extend(e.Controller.prototype,e.Events,{route:function(a,b,c){e.history||(e.history=new e.History);f.isRegExp(a)||(a=this._routeToRegExp(a));e.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d))},this))},saveLocation:function(a){e.history.saveLocation(a)},_bindRoutes:function(){if(this.routes)for(var a in this.routes){var b=this.routes[a];
|
20
|
+
this.route(a,b,this[b])}},_routeToRegExp:function(a){a=a.replace(o,"([^/]*)").replace(p,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});e.History=function(){this.handlers=[];this.fragment=this.getFragment();f.bindAll(this,"checkUrl")};var k=/^#*/;f.extend(e.History.prototype,{interval:50,getFragment:function(a){return(a||window.location).hash.replace(k,"")},start:function(){var a=document.documentMode;if(a=h.browser.msie&&a<7)this.iframe=h('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow;
|
21
|
+
"onhashchange"in window&&!a?h(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);return this.loadUrl()},route:function(a,b){this.handlers.push({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();if(a==this.fragment&&this.iframe)a=this.getFragment(this.iframe.location);if(a==this.fragment||a==decodeURIComponent(this.fragment))return false;if(this.iframe)window.location.hash=this.iframe.location.hash=a;this.loadUrl()},loadUrl:function(){var a=this.fragment=
|
22
|
+
this.getFragment();return f.any(this.handlers,function(b){if(b.route.test(a)){b.callback(a);return true}})},saveLocation:function(a){a=(a||"").replace(k,"");if(this.fragment!=a){window.location.hash=this.fragment=a;if(this.iframe&&a!=this.getFragment(this.iframe.location)){this.iframe.document.open().close();this.iframe.location.hash=a}}}});e.View=function(a){this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize&&this.initialize(a)};var l=function(a){return h(a,this.el)},
|
23
|
+
q=/^(\w+)\s*(.*)$/;f.extend(e.View.prototype,e.Events,{tagName:"div",$:l,jQuery:l,render:function(){return this},remove:function(){h(this.el).remove();return this},make:function(a,b,c){a=document.createElement(a);b&&h(a).attr(b);c&&h(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events)){h(this.el).unbind();for(var b in a){var c=a[b],d=b.match(q),g=d[1];d=d[2];c=f.bind(this[c],this);d===""?h(this.el).bind(g,c):h(this.el).delegate(d,g,c)}}},_configure:function(a){if(this.options)a=
|
24
|
+
f.extend({},this.options,a);if(a.model)this.model=a.model;if(a.collection)this.collection=a.collection;if(a.el)this.el=a.el;if(a.id)this.id=a.id;if(a.className)this.className=a.className;if(a.tagName)this.tagName=a.tagName;this.options=a},_ensureElement:function(){if(!this.el){var a={};if(this.id)a.id=this.id;if(this.className)a.className=this.className;this.el=this.make(this.tagName,a)}}});var m=function(a,b){var c=r(this,a,b);c.extend=m;return c};e.Model.extend=e.Collection.extend=e.Controller.extend=
|
25
|
+
e.View.extend=m;var s={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,b,c,d){var g=s[a];a=a==="create"||a==="update"?JSON.stringify(b.toJSON()):null;b={url:j(b),type:g,contentType:"application/json",data:a,dataType:"json",processData:false,success:c,error:d};if(e.emulateJSON){b.contentType="application/x-www-form-urlencoded";b.processData=true;b.data=a?{model:a}:{}}if(e.emulateHTTP)if(g==="PUT"||g==="DELETE"){if(e.emulateJSON)b.data._method=g;b.type="POST";b.beforeSend=
|
26
|
+
function(i){i.setRequestHeader("X-HTTP-Method-Override",g)}}h.ajax(b)};var n=function(){},r=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};n.prototype=a.prototype;d.prototype=new n;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},j=function(a){if(!(a&&a.url))throw Error("A 'url' property or function must be specified");return f.isFunction(a.url)?a.url():a.url}})();
|
@@ -0,0 +1,42 @@
|
|
1
|
+
body {
|
2
|
+
padding: 0;
|
3
|
+
margin: 0;
|
4
|
+
}
|
5
|
+
ul#columns {
|
6
|
+
list-style-type: none;
|
7
|
+
height: 200px;
|
8
|
+
margin: 0;
|
9
|
+
padding: 0;
|
10
|
+
}
|
11
|
+
ul#columns>li {
|
12
|
+
display: inline-block;
|
13
|
+
height: 200px;
|
14
|
+
width: 33%;
|
15
|
+
overflow: scroll;
|
16
|
+
margin: 0;
|
17
|
+
padding: 0;
|
18
|
+
}
|
19
|
+
ul#columns>li:first {
|
20
|
+
width: 34%;
|
21
|
+
}
|
22
|
+
|
23
|
+
ul#columns>li>h1 {
|
24
|
+
font-size: 12pt;
|
25
|
+
margin: 0;
|
26
|
+
}
|
27
|
+
|
28
|
+
ul#columns>li>ul {
|
29
|
+
margin: 0;
|
30
|
+
padding: 0;
|
31
|
+
}
|
32
|
+
|
33
|
+
ul#columns>li>ul>li {
|
34
|
+
padding-left: 0.2em;
|
35
|
+
}
|
36
|
+
#content {
|
37
|
+
padding: 0 1em;
|
38
|
+
}
|
39
|
+
#content h1 {
|
40
|
+
margin-top: 0.2em;
|
41
|
+
margin-bottom: 0;
|
42
|
+
}
|