cans 0.1.2 → 0.2.0
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 +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
|
+
}
|