mud 0.0.4

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.
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mud.gemspec
4
+ gemspec
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mud (0.0.4)
5
+ hpricot (>= 0.8.4)
6
+ sinatra (>= 1.1.2)
7
+ thor (>= 0.14.6)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ hpricot (0.8.4)
13
+ rack (1.2.2)
14
+ sinatra (1.1.2)
15
+ rack (~> 1.1)
16
+ tilt (~> 1.2)
17
+ thor (0.14.6)
18
+ tilt (1.2.2)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ hpricot (>= 0.8.4)
25
+ mud!
26
+ sinatra (>= 1.1.2)
27
+ thor (>= 0.14.6)
@@ -0,0 +1,2 @@
1
+ Ruby port of Mud (package manager for client-side Javascript).
2
+ See [http://github.com/mafintosh/mud](http://github.com/mafintosh/mud) for (non-existing) documentation.
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/bin/mud ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+
5
+ require 'mud'
6
+ require 'mud/cli'
7
+
8
+ begin
9
+ Mud::CLI.start
10
+ rescue Mud::ResolveError => err
11
+ puts err.message, "Try running: mud install #{err.name}"
12
+ rescue Interrupt
13
+ puts "Quitting..."
14
+ end
@@ -0,0 +1,219 @@
1
+ if (typeof JSON === 'undefined') { // Fixed from the original JSON to support Google Closure compilation
2
+ JSON = {};
3
+ }
4
+
5
+ (function () {
6
+ "use strict";
7
+
8
+ function f(n) {
9
+ // Format integers to have at least two digits.
10
+ return n < 10 ? '0' + n : n;
11
+ }
12
+
13
+ if (typeof Date.prototype.toJSON !== 'function') {
14
+
15
+ Date.prototype.toJSON = function (key) {
16
+
17
+ return isFinite(this.valueOf()) ?
18
+ this.getUTCFullYear() + '-' +
19
+ f(this.getUTCMonth() + 1) + '-' +
20
+ f(this.getUTCDate()) + 'T' +
21
+ f(this.getUTCHours()) + ':' +
22
+ f(this.getUTCMinutes()) + ':' +
23
+ f(this.getUTCSeconds()) + 'Z' : null;
24
+ };
25
+
26
+ String.prototype.toJSON =
27
+ Number.prototype.toJSON =
28
+ Boolean.prototype.toJSON = function (key) {
29
+ return this.valueOf();
30
+ };
31
+ }
32
+
33
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
34
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
35
+ gap,
36
+ indent,
37
+ meta = { // table of character substitutions
38
+ '\b': '\\b',
39
+ '\t': '\\t',
40
+ '\n': '\\n',
41
+ '\f': '\\f',
42
+ '\r': '\\r',
43
+ '"' : '\\"',
44
+ '\\': '\\\\'
45
+ },
46
+ rep;
47
+
48
+
49
+ function quote(string) {
50
+
51
+ escapable.lastIndex = 0;
52
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
53
+ var c = meta[a];
54
+ return typeof c === 'string' ? c :
55
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
56
+ }) + '"' : '"' + string + '"';
57
+ }
58
+
59
+
60
+ function str(key, holder) {
61
+
62
+ var i, // The loop counter.
63
+ k, // The member key.
64
+ v, // The member value.
65
+ length,
66
+ mind = gap,
67
+ partial,
68
+ value = holder[key];
69
+
70
+ if (value && typeof value === 'object' &&
71
+ typeof value.toJSON === 'function') {
72
+ value = value.toJSON(key);
73
+ }
74
+
75
+ if (typeof rep === 'function') {
76
+ value = rep.call(holder, key, value);
77
+ }
78
+
79
+ switch (typeof value) {
80
+ case 'string':
81
+ return quote(value);
82
+
83
+ case 'number':
84
+
85
+ return isFinite(value) ? String(value) : 'null';
86
+
87
+ case 'boolean':
88
+ case 'null':
89
+
90
+ return String(value);
91
+
92
+ case 'object':
93
+
94
+ if (!value) {
95
+ return 'null';
96
+ }
97
+
98
+ gap += indent;
99
+ partial = [];
100
+
101
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
102
+
103
+ length = value.length;
104
+ for (i = 0; i < length; i += 1) {
105
+ partial[i] = str(i, value) || 'null';
106
+ }
107
+
108
+ v = partial.length === 0 ? '[]' : gap ?
109
+ '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
110
+ '[' + partial.join(',') + ']';
111
+ gap = mind;
112
+ return v;
113
+ }
114
+
115
+ if (rep && typeof rep === 'object') {
116
+ length = rep.length;
117
+ for (i = 0; i < length; i += 1) {
118
+ if (typeof rep[i] === 'string') {
119
+ k = rep[i];
120
+ v = str(k, value);
121
+ if (v) {
122
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
123
+ }
124
+ }
125
+ }
126
+ } else {
127
+
128
+ for (k in value) {
129
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
130
+ v = str(k, value);
131
+ if (v) {
132
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
133
+ }
134
+ }
135
+ }
136
+ }
137
+
138
+ v = partial.length === 0 ? '{}' : gap ?
139
+ '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
140
+ '{' + partial.join(',') + '}';
141
+ gap = mind;
142
+ return v;
143
+ }
144
+ }
145
+
146
+ if (typeof JSON.stringify !== 'function') {
147
+ JSON.stringify = function (value, replacer, space) {
148
+
149
+ var i;
150
+ gap = '';
151
+ indent = '';
152
+
153
+ if (typeof space === 'number') {
154
+ for (i = 0; i < space; i += 1) {
155
+ indent += ' ';
156
+ }
157
+
158
+ } else if (typeof space === 'string') {
159
+ indent = space;
160
+ }
161
+
162
+ rep = replacer;
163
+ if (replacer && typeof replacer !== 'function' &&
164
+ (typeof replacer !== 'object' ||
165
+ typeof replacer.length !== 'number')) {
166
+ throw new Error('JSON.stringify');
167
+ }
168
+
169
+ return str('', {'': value});
170
+ };
171
+ }
172
+
173
+ if (typeof JSON.parse !== 'function') {
174
+ JSON.parse = function (text, reviver) {
175
+
176
+ var j;
177
+
178
+ function walk(holder, key) {
179
+
180
+ var k, v, value = holder[key];
181
+ if (value && typeof value === 'object') {
182
+ for (k in value) {
183
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
184
+ v = walk(value, k);
185
+ if (v !== undefined) {
186
+ value[k] = v;
187
+ } else {
188
+ delete value[k];
189
+ }
190
+ }
191
+ }
192
+ }
193
+ return reviver.call(holder, key, value);
194
+ }
195
+
196
+ text = String(text);
197
+ cx.lastIndex = 0;
198
+ if (cx.test(text)) {
199
+ text = text.replace(cx, function (a) {
200
+ return '\\u' +
201
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
202
+ });
203
+ }
204
+
205
+ if (/^[\],:{}\s]*$/
206
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
207
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
208
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
209
+
210
+ j = eval('(' + text + ')');
211
+
212
+ return typeof reviver === 'function' ?
213
+ walk({'': j}, '') : j;
214
+ }
215
+
216
+ throw new SyntaxError('JSON.parse');
217
+ };
218
+ }
219
+ }());
@@ -0,0 +1,10 @@
1
+
2
+ (function(require) {
3
+ <%= render :erb => 'inline_modules.js.erb', :locals => { :modules => modules } %>
4
+
5
+ <% modules.each do |mod| %>
6
+ window[<%= mod.name.to_json %>] = require(<%= mod.name.to_json %>);
7
+ <% end %>
8
+ })();
9
+
10
+ <%= render :erb => 'list.js.erb', :locals => { :list => appends } %>
@@ -0,0 +1,12 @@
1
+
2
+ <%= render :file => 'require.js' %>
3
+
4
+ <%= render :file => 'JSON.js' %>
5
+
6
+ <% modules.each do |mod| %>
7
+ require.define(<%= mod.name.to_json %>, function(module, exports) {
8
+ <%= mod.content %>
9
+ });
10
+ <% end %>
11
+
12
+ <%= render :erb => 'list.js.erb', :locals => { :list => appends } if defined?(appends) %>
@@ -0,0 +1,3 @@
1
+ <% list.each do |item| %>
2
+ <%= item %>
3
+ <% end %>
@@ -0,0 +1,42 @@
1
+ (function() {
2
+ if (typeof require !== 'undefined') {
3
+ return; // define only once
4
+ }
5
+
6
+ var noop = function() {};
7
+ var modules = {};
8
+ var definitions = {};
9
+
10
+ require = function(name) {
11
+ if (arguments.length > 1) { // this syntax allows for and module and it's plugins to be loaded
12
+ var val = require(arguments[0]);
13
+
14
+ for (var i = 1; i < arguments.length; i++) {
15
+ require(arguments[i]);
16
+ }
17
+ return val;
18
+ }
19
+ name = name.split('@')[0]; // TODO: make this versioning a lot better
20
+
21
+ if (definitions[name] && !modules[name]) { // if not already loaded and an def exists
22
+ var def = definitions[name];
23
+
24
+ delete definitions[name];
25
+
26
+ var module = modules[name] = function() {
27
+ return module.exports;
28
+ };
29
+
30
+ module.browser = true; // allows for non-hacky browser js detection
31
+ module.exports = {};
32
+
33
+ def(module, module.exports);
34
+ }
35
+
36
+ return window[name] || (modules[name] || noop)();
37
+ };
38
+
39
+ require.define = function(name, def) {
40
+ definitions[name] = def;
41
+ };
42
+ }());
@@ -0,0 +1,18 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
2
+
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'json'
6
+ require 'erb'
7
+ require 'rbconfig'
8
+
9
+ require 'sinatra/base'
10
+ require 'thor'
11
+ require 'hpricot'
12
+
13
+ module Mud
14
+ require 'mud/utils'
15
+ extend Mud::Utils
16
+ end
17
+
18
+ %w(context dependency js_result html_result module installed_module server).each { |f| require "mud/#{f}" }
@@ -0,0 +1,65 @@
1
+ module Mud
2
+
3
+ class CLI < Thor
4
+ include Thor::Actions
5
+
6
+ def initialize(*)
7
+ super
8
+ @context = Mud::Context.new
9
+ say("(in #{@context.dir})")
10
+ end
11
+
12
+ map "ls" => "list"
13
+
14
+ desc "resolve PATH", "resolve the given path"
15
+ method_option :compile, :default => nil, :desc => "compile loaded modules"
16
+ def resolve(path)
17
+ modules = @context.resolve_document(path)
18
+ result = Mud::JsResult.new(modules, :compile => options[:compile])
19
+ say(result.to_s)
20
+ end
21
+
22
+ desc "inline PATH", "resolve and inline the given path"
23
+ method_option :compile, :default => nil, :desc => "compile loaded modules"
24
+ def inline(path)
25
+ result = @context.inline_document(path, :compile => options[:compile])
26
+ say(result.to_s)
27
+ end
28
+
29
+ desc "module A,B,...,C", "load in these modules"
30
+ method_option :compile, :default => nil, :desc => "compile loaded modules"
31
+ #method_option :output, :default => nil, :desc => "output file"
32
+ def modules(modules)
33
+ modules = modules.split(',').map { |mod_name| @context.module!(mod_name) }
34
+ result = @context.inline(modules, :compile => options[:compile])
35
+
36
+ if out = options[:output]
37
+ File.open(out, 'w') { |f| f.write(result.to_s) }
38
+ else
39
+ say(result.to_s)
40
+ end
41
+ end
42
+
43
+ desc "server", "run a mud server"
44
+ #method_options :fork, :default => false, :desc => "run the server as a daemon (only supported on unix platforms)"
45
+ def server
46
+ Mud::Server.context = @context
47
+ Mud::Server.run!
48
+ end
49
+
50
+ desc "list", "list all installed packages"
51
+ method_option :path, :default => false, :desc => "include module paths"
52
+ def list
53
+ modules = @context.available_modules.values
54
+ if modules.empty?
55
+ say("no modules found")
56
+ else
57
+ modules.each do |m|
58
+ msg = m.name + (options[:path] ? " => #{m.path}" : '')
59
+ say(msg)
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ end
@@ -0,0 +1,167 @@
1
+ module Mud
2
+
3
+ class ResolveError < StandardError
4
+ attr_reader :name
5
+
6
+ def initialize(name_or_dependency)
7
+ @name = name_or_dependency.is_a?(Mud::Dependency) ? name_or_dependency.name : name_or_dependency
8
+ super("No module named '#{@name}' in context")
9
+ end
10
+ end
11
+
12
+ class Context
13
+ MODULE_DIRECTORIES = ['js_modules', 'shared_modules']
14
+ MODULE_GLOBAL = Mud.home_directory('.mud', 'js_modules')
15
+
16
+ attr_reader :available_modules, :dir
17
+
18
+ def initialize(dir = '.')
19
+ @dir = File.absolute_path(dir)
20
+ @available_modules = {}
21
+ reload
22
+ end
23
+
24
+ def reload
25
+ dirs = dirs(@dir)
26
+ removed = @available_modules.dup
27
+
28
+ dirs.each do |dir|
29
+ Dir.glob(File.join(dir, '*.js')) do |mod_path|
30
+ name = Mud::Module.parse_name(mod_path)
31
+ mod = @available_modules[name]
32
+ removed.delete(name)
33
+
34
+ unless mod and mod.modified == File.mtime(mod_path) and mod.path == mod_path
35
+ @available_modules[name] = Mud::InstalledModule.new(mod_path, self)
36
+ end
37
+ end
38
+ end
39
+
40
+ @available_modules.delete_if { |key, _| removed.key?(key) }
41
+ end
42
+
43
+ def install(name, opts = {})
44
+ return if @available_modules[name]# or raise exception
45
+
46
+ src = nil # download module src from mudhub and write to disk in module global
47
+ path = nil
48
+
49
+ @available_modules[name] = Mud::InstalledModule.new(path, self) # check dependencies and download if not present
50
+ end
51
+
52
+ def uninstall(module_or_name)
53
+ end
54
+
55
+ def module(name)
56
+ @available_modules[name]
57
+ end
58
+
59
+ def module!(name)
60
+ @available_modules[name] || (raise Mud::ResolveError.new(name))
61
+ end
62
+
63
+ def resolve_document(path)
64
+ resolve analyze_document(path).first
65
+ end
66
+
67
+ def inline_document(path, opts = {})
68
+ modules, type = analyze_document(path)
69
+
70
+ result = inline(modules, opts)
71
+
72
+ if type == :js
73
+ main = modules.first
74
+ result << main.content
75
+ else
76
+ result = Mud::HtmlResult.new(path, result)
77
+ end
78
+
79
+ result
80
+ end
81
+
82
+ def resolve(module_or_list)
83
+ modules = module_or_list.is_a?(Mud::Module) ? [module_or_list] : module_or_list
84
+
85
+ resolved = []
86
+
87
+ resolver = proc do |modules|
88
+ modules.each do |mod|
89
+ next if resolved.include?(mod)
90
+ resolved.unshift(mod) if mod.is_a?(Mud::InstalledModule)
91
+
92
+ dep = mod.unresolvable_dependencies.first
93
+ raise Mud::ResolveError.new(dep) if dep
94
+
95
+ dependencies = mod.dependencies.map(&:resolve).delete_if { |m| resolved.include?(m) }
96
+ resolver.call(dependencies) unless dependencies.empty?
97
+ end
98
+ end
99
+ resolver.call(modules)
100
+
101
+ resolved
102
+ end
103
+
104
+ def inline(module_or_list, opts = {})
105
+ resolved = resolve(module_or_list)
106
+ Mud::JsResult.new(resolved, opts)
107
+ end
108
+
109
+ private
110
+
111
+ def analyze_document(path)
112
+ content = Mud.render path
113
+ type = content.match(/^\s*</) ? :html : :js
114
+
115
+ modules = if type == :html
116
+ analyze_html(path, content)
117
+ else
118
+ [Mud::Module.new(path, content, self)]
119
+ end
120
+
121
+ return modules, type
122
+ end
123
+
124
+ def analyze_html(path, html)
125
+ inner_modules = []
126
+ doc = Hpricot(html)
127
+
128
+ doc.search('//script').each do |script_tag|
129
+ src = script_tag.attributes['src']
130
+
131
+ if src and not src.empty? and not src.match(/^\w+:\/\//)
132
+ begin
133
+ content = Mud.render src, :basepath => path
134
+ inner_modules << Mud::Module.new(src, content, self)
135
+ rescue Errno::ENOENT, Net::HTTPError
136
+ # Does not exist. Ignore.
137
+ end
138
+ end
139
+
140
+ content = script_tag.inner_html
141
+ if content and not content.empty?
142
+ inner_modules << Mud::Module.new("#{File.basename(path)}-embedded-script-#{inner_modules.length}", content, self)
143
+ end
144
+ end
145
+
146
+ inner_modules
147
+ end
148
+
149
+ def dirs(start)
150
+ dirs = [MODULE_GLOBAL]
151
+
152
+ current = File.absolute_path(start)
153
+ while true
154
+ dirs += MODULE_DIRECTORIES.map { |dir| File.join(current, dir) }
155
+ break if current == Mud.root_directory
156
+ current = File.expand_path(current, '..')
157
+ end
158
+
159
+ dirs.keep_if { |dir| File.exists?(dir) }
160
+ end
161
+
162
+ def in(*paths)
163
+ File.join(@dir, *paths)
164
+ end
165
+ end
166
+
167
+ end
@@ -0,0 +1,40 @@
1
+ module Mud
2
+
3
+ class Dependency
4
+ def self.analyze(src, context)
5
+ dependencies = Set.new
6
+
7
+ # Find all required files on the form require('name') og require('name', 'sub_name', ...)
8
+ src.scan(/require\(((?:'[^']+'(?:,\s)?)+)\)/).each do |req|
9
+ req.first.scan(/'([^']+)'/).each { |name| dependencies << new(name.first, context) }
10
+ end
11
+
12
+ dependencies.to_a
13
+ end
14
+
15
+ attr_reader :name, :context
16
+
17
+ def initialize(name, context)
18
+ @name = name
19
+ @context = context
20
+ end
21
+
22
+ def to_s
23
+ "Mud::Dependency #{@name}"
24
+ end
25
+
26
+ def ==(other)
27
+ other.is_a?(self.class) and other.name == @name
28
+ end
29
+
30
+ def resolvable?
31
+ !!resolve
32
+ end
33
+
34
+ # Resolves to the corresponding module if present in this context.
35
+ def resolve
36
+ @context.module(@name)
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,39 @@
1
+ module Mud
2
+
3
+ class HtmlResult
4
+ def initialize(html, js)
5
+ @html = html
6
+ @js = js
7
+ end
8
+
9
+ def to_s
10
+ doc = html_doc
11
+ script = doc.search('//script').find { |script_tag| /.*\/dev$/.match script_tag.attributes['src'] }
12
+
13
+ if script
14
+ script.remove_attribute(:src)
15
+ else
16
+ script = Hpricot::Elem.new('script', :type => 'text/javascript')
17
+ head = doc.at('/html/head')
18
+
19
+ unless head
20
+ head = Hpricot::Elem.new('head')
21
+ doc.root.children.unshift(head)
22
+ end
23
+
24
+ head.children = (head.children || []).unshift(script)
25
+ end
26
+
27
+ script.inner_html = @js.to_s
28
+
29
+ doc.to_html
30
+ end
31
+
32
+ private
33
+
34
+ def html_doc
35
+ Hpricot(Mud.render @html)
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,19 @@
1
+ module Mud
2
+
3
+ class InstalledModule < Mud::Module
4
+ attr_reader :path, :modified
5
+
6
+ def initialize(path, context)
7
+ super(path, File.open(path) { |f| f.read }, context)
8
+ @content = nil
9
+
10
+ @path = path
11
+ @modified = File.mtime(path)
12
+ end
13
+
14
+ def content
15
+ File.open(@path) { |f| f.read }
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,25 @@
1
+ module Mud
2
+
3
+ class JsResult
4
+ def initialize(modules, opts = {})
5
+ opts = { :global => false, :compile => nil }.update(opts)
6
+
7
+ @modules = modules
8
+ @global = opts[:global]
9
+ @compile = opts[:compile]
10
+
11
+ @appends = []
12
+ end
13
+
14
+ def to_s
15
+ result = Mud.render :erb => (@global ? 'global.js.erb' : 'inline_modules.js.erb'),
16
+ :locals => { :modules => @modules, :appends => @appends }, :basepath => Mud.js_directory
17
+ @compile ? Mud.compile(result, @compile) : result
18
+ end
19
+
20
+ def <<(src)
21
+ @appends << src
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,39 @@
1
+ module Mud
2
+
3
+ class Module
4
+ attr_reader :name, :content, :context, :dependencies
5
+
6
+ def self.parse_name(path_or_name)
7
+ File.basename(path_or_name).split(/\.js$/i).first
8
+ end
9
+
10
+ def initialize(name, content, context)
11
+ @name = self.class.parse_name(name)
12
+ @content = content
13
+ @context = context
14
+
15
+ @dependencies = Mud::Dependency.analyze(content, context)
16
+ end
17
+
18
+ def to_s
19
+ "#{self.class} #{@name}"
20
+ end
21
+
22
+ def ==(other)
23
+ other.is_a?(self.class) and other.name == @name
24
+ end
25
+
26
+ def unresolvable_dependencies
27
+ @dependencies.select { |d| not d.resolvable? }
28
+ end
29
+
30
+ def resolvable?
31
+ @dependencies.all?(&:resolvable?)
32
+ end
33
+
34
+ def depends_on?(module_or_dependency)
35
+ !!@dependencies.find { |d| d.name == module_or_dependency.name }
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,86 @@
1
+ module Mud
2
+
3
+ class Server < Sinatra::Base
4
+ enable :logging, :dump_errors, :inline_templates
5
+ disable :static, :run
6
+
7
+ set :port, 10000
8
+
9
+ class << self
10
+ def port=(port)
11
+ set :port, port
12
+ end
13
+
14
+ def context=(context)
15
+ @@context = context
16
+ end
17
+ end
18
+
19
+ helpers do
20
+ def context
21
+ unless defined?(@@context)
22
+ @@context = Mud::Context.new
23
+ else
24
+ @@context.reload
25
+ end
26
+
27
+ @@context
28
+ end
29
+
30
+ def js
31
+ content_type 'application/javascript'
32
+ end
33
+
34
+ def process_modules(modules, opts)
35
+ halt 400 if modules.nil? or modules.empty?
36
+ modules = modules.split(',').map { |name| context.module!(name) }
37
+ context.inline(modules, opts).to_s
38
+ end
39
+ end
40
+
41
+ get '/dev' do
42
+ ref = params[:ref] || request.referrer
43
+
44
+ js
45
+ if ref.nil? or ref == '/'
46
+ host = "#{request.host.split(':').first}:#{settings.port}"
47
+ erb :dev, :locals => { :host => host }
48
+ else
49
+ modules = context.resolve_document(ref)
50
+ Mud::JsResult.new(modules).to_s
51
+ end
52
+ end
53
+
54
+ get '/m/:modules' do |modules|
55
+ js
56
+ process_modules(modules, :global => false)
57
+ end
58
+
59
+ get '/g/:modules' do |modules|
60
+ js
61
+ process_modules(modules, :global => true)
62
+ end
63
+
64
+ get '/p/:var' do |var|
65
+ content_type 'text/html'
66
+ erb :play, :locals => { :var => var }
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ __END__
73
+
74
+ @@ dev
75
+ document.write('<script src="http://<%= host %>/dev?ref=' + window.location + '"></script>');
76
+
77
+ @@ play
78
+ <!DOCTYPE html>
79
+ <html>
80
+ <head>
81
+ <title>mud play</title>
82
+ <script src="<%= "/m/#{var}" %>"></script>
83
+ </head>
84
+ <body>
85
+ </body>
86
+ </html>
@@ -0,0 +1,146 @@
1
+ module Mud
2
+
3
+ File.class_eval do
4
+ def self.hide(file_name, force_rename = false)
5
+ os = RbConfig::CONFIG['host_os']
6
+
7
+ if os =~ /mswin|windows|cygwin/i
8
+ raise IOError.new("Could not hide file '#{file_name}' using attrib +h") unless system("attrib +h '#{file_name}'")
9
+ file_name
10
+ else
11
+ # Assume unix-like
12
+
13
+ parent, base = dirname(file_name), basename(file_name)
14
+
15
+ if base.start_with?('.')
16
+ file_name
17
+ else
18
+ if os =~ /darwin/i and not force_rename
19
+ # OS X
20
+ raise IOError.new("Could not hide file '#{file_name}' using SetFile -a -V") unless system("SetFile -a V '#{file_name}'")
21
+ return file_name
22
+ end
23
+
24
+ hidden = join(parent, ".#{base}")
25
+ raise IOError.new("Can't hide '#{file_name}' by renaming to '#{hidden} (already exists)") if exists?(hidden)
26
+ rename(file_name, hidden)
27
+ hidden
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ module Utils
34
+ JS_DIRECTORY = File.expand_path(File.join File.dirname(__FILE__), '..', '..', 'js')
35
+
36
+ ROOT_DIRECTORY = File.absolute_path('/')
37
+ HOME_DIRECTORY = Dir.home
38
+
39
+ [:js, :root, :home].each do |name|
40
+ name = "#{name}_directory"
41
+ module_eval %{
42
+ def #{name}(*paths)
43
+ File.join(#{name.upcase}, *paths)
44
+ end
45
+ }
46
+ end
47
+
48
+ def compile(src, type = 'simple', out = nil)
49
+ raise ArgumentError.new("Type must be either 'simple' or 'advanced', was '#{type}'") unless ['simple', 'advanced'].include?(type.to_s)
50
+ level = "#{type.upcase}_OPTIMIZATIONS"
51
+
52
+ response = Net::HTTP.post_form(URI.parse('http://closure-compiler.appspot.com/compile'),
53
+ :output_info => 'compiled_code',
54
+ :compilation_level => level,
55
+ :warning_level => 'default',
56
+ :js_code => src)
57
+
58
+ if out
59
+ File.open(out) { |f| f.write(response.body) }
60
+ end
61
+
62
+ response.body
63
+ end
64
+
65
+ def render(location, opts = {})
66
+ if location.is_a?(Hash)
67
+ opts = location
68
+ else
69
+ opts = guess(location).update(opts)
70
+ end
71
+
72
+ type, path = opts.first
73
+
74
+ content = case type
75
+ when :erb, :file then
76
+ basepath = opts[:basepath] || path
77
+ basepath = basepath.gsub(/^file:\/\//, '')
78
+
79
+ path = opts[:basepath] ? File.join(basepath, path) : basepath
80
+
81
+ File.open(path) { |f| f.read }
82
+ when :http then
83
+ basepath = opts[:basepath] || path
84
+ basepath = "http://#{basepath}" unless basepath.start_with?('http://')
85
+
86
+ path = opts[:basepath] ? URI.join(basepath, path) : basepath
87
+
88
+ response = Net::HTTP.get_response(URI.parse(path))
89
+ response.error! unless (200..299).include?(response.code.to_i)
90
+ response.body
91
+ else
92
+ raise ArgumentError.new("Unknown type '#{type}'")
93
+ end
94
+
95
+ if type == :erb
96
+ locals = opts[:locals] || {}
97
+ content = ERB.new(content).result(LocalsBinding.new(locals).binding)
98
+ end
99
+
100
+ content
101
+ end
102
+ alias :cat :render
103
+
104
+ private
105
+
106
+ class LocalsBinding < BasicObject
107
+ def initialize(locals, &block)
108
+ @_locals = locals
109
+
110
+ locals.each_pair do |name, value|
111
+ instance_eval %{
112
+ def #{name}
113
+ _get(:#{name})
114
+ end
115
+ }
116
+ end
117
+
118
+ instance_eval(&block) if block
119
+ end
120
+
121
+ def js_directory(*paths)
122
+ ::Mud.js_directory(*paths)
123
+ end
124
+
125
+ def render(opts)
126
+ ::Mud.render(opts.update :basepath => js_directory)
127
+ end
128
+
129
+ def binding
130
+ ::Proc.new {}.binding
131
+ end
132
+
133
+ private
134
+
135
+ def _get(name)
136
+ @_locals[name.to_sym] || @_locals[name.to_s]
137
+ end
138
+ end
139
+
140
+ def guess(path)
141
+ protocol = (path.match(/^(\w+):\/\//) || [])[1] || 'file'
142
+ { protocol.to_sym => path }
143
+ end
144
+ end
145
+
146
+ end
@@ -0,0 +1,3 @@
1
+ module Mud
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mud/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "mud"
7
+ s.version = Mud::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Mirza Kapetanovic", "Mathias Buus"]
10
+ #s.email = [""]
11
+ s.homepage = "http://mudhub.org"
12
+ s.summary = %q{Simple browser Javascript package manager}
13
+ s.description = %q{Mud is a simple package manager for client-side Javascript. Used for installing new packages and resolving dependencies.}
14
+
15
+ #s.rubyforge_project = "mud"
16
+
17
+ s.add_dependency("sinatra", ">= 1.1.2")
18
+ s.add_dependency("thor", ">= 0.14.6")
19
+ s.add_dependency("hpricot", ">= 0.8.4")
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ #s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = ["mud"]
24
+ s.require_paths = ["lib"]
25
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mud
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 4
9
+ version: 0.0.4
10
+ platform: ruby
11
+ authors:
12
+ - Mirza Kapetanovic
13
+ - Mathias Buus
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-29 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: sinatra
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 1
31
+ - 1
32
+ - 2
33
+ version: 1.1.2
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: thor
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ segments:
45
+ - 0
46
+ - 14
47
+ - 6
48
+ version: 0.14.6
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: hpricot
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 0
61
+ - 8
62
+ - 4
63
+ version: 0.8.4
64
+ type: :runtime
65
+ version_requirements: *id003
66
+ description: Mud is a simple package manager for client-side Javascript. Used for installing new packages and resolving dependencies.
67
+ email:
68
+ executables:
69
+ - mud
70
+ extensions: []
71
+
72
+ extra_rdoc_files: []
73
+
74
+ files:
75
+ - .gitignore
76
+ - Gemfile
77
+ - Gemfile.lock
78
+ - README.md
79
+ - Rakefile
80
+ - bin/mud
81
+ - js/JSON.js
82
+ - js/global.js.erb
83
+ - js/inline_modules.js.erb
84
+ - js/list.js.erb
85
+ - js/require.js
86
+ - lib/mud.rb
87
+ - lib/mud/cli.rb
88
+ - lib/mud/context.rb
89
+ - lib/mud/dependency.rb
90
+ - lib/mud/html_result.rb
91
+ - lib/mud/installed_module.rb
92
+ - lib/mud/js_result.rb
93
+ - lib/mud/module.rb
94
+ - lib/mud/server.rb
95
+ - lib/mud/utils.rb
96
+ - lib/mud/version.rb
97
+ - mud.gemspec
98
+ has_rdoc: true
99
+ homepage: http://mudhub.org
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options: []
104
+
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ segments:
113
+ - 0
114
+ version: "0"
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ requirements: []
124
+
125
+ rubyforge_project:
126
+ rubygems_version: 1.3.7
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: Simple browser Javascript package manager
130
+ test_files: []
131
+