Skip to content

Commit

Permalink
Allow simultaneous exporting and dependency resolving of numerous mod…
Browse files Browse the repository at this point in the history
…ules.
  • Loading branch information
tobie committed Oct 31, 2010
1 parent 41b83b6 commit 71bc880
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 41 deletions.
19 changes: 13 additions & 6 deletions README.markdown
Expand Up @@ -41,25 +41,32 @@ To process a JavaScript source file, just run:

$ modulrize filename.js > output.js

You can also simultaneously process multiples files like so:

$ modulrize filename.js other_filename.js > output.js

Options are as follows:

-o, --output=FILE Write the output to FILE. Defaults to stdout.
-r, --root=DIR Set DIR as root directory. Defaults to the directory containing FILE.
--lazy-eval [MODULES] Enable lazy evaluation of all JS modules or of those specified by MODULES.
MODULES accepts a comma-separated list of identifiers.
--minify Minify output using YUI Compressor.
--global-export=GLOBAL_VAR Export main module's exports to the GLOBAL_VAR global variable.
--sync Avoid using require.ensure.
--global-export[=GLOBAL_VAR] If GLOBAL_VAR is specified and only one module is being processed, exports it to the GLOBAL_VAR global variable.
If GLOBAL_VAR is specified and multiple modules are being processed, exports each one of them as a property of GLOBAL_VAR.
If GLOBAL_VAR isn't specified, exports the module to global variables corresponding to their identifier.
--sync Load all dependencies synchronously.
--dependency-graph[=OUTPUT] Create a dependency graph of the module.
-h, --help Show this message.

Minification options (these are forwarded to YUI Compressor without the "minify-" prefix):

--minify-disable-optimizations Disable all micro optimizations.
--minify-nomunge Minify only, do not obfuscate.
--minify-verbose Display informational messages and warnings.
--minify-line-break COLUMN Insert a line break after the specified column number.
--minify-preserve-semi Preserve all semicolons.
--minify-nomunge Minify only, do not obfuscate.
--minify-verbose Display informational messages and warnings.
--minify-line-break COLUMN Insert a line break after the specified column number.
--minify-preserve-semi Preserve all semicolons.


Specs
-----
Expand Down
8 changes: 5 additions & 3 deletions bin/modulrize
Expand Up @@ -31,8 +31,8 @@ opts = OptionParser.new do |opts|
options[:minify] = minify
end

opts.on('--global-export=GLOBAL_VAR', 'Export main module\'s exports to the GLOBAL_VAR global variable.') do |global|
options[:global] = global
opts.on('--global-export[=GLOBAL_VAR]', 'If GLOBAL_VAR is specified and only one module is being processed, exports it to the GLOBAL_VAR global variable.', 'If GLOBAL_VAR is specified and multiple modules are being processed, exports each one of them as a property of GLOBAL_VAR.', 'If GLOBAL_VAR isn\'t specified, exports the module to global variables corresponding to their identifier.') do |global|
options[:global] = global || true
end

opts.on('--sync', 'Load all dependencies synchronously.') do |global|
Expand Down Expand Up @@ -87,7 +87,9 @@ begin
if options.delete(:dependency_graph)
result = Modulr.graph(ARGV.first, options)
else
result = Modulr.ize(ARGV.first, options)
args = opts.default_argv.dup
args << options
result = Modulr.ize(*args)
output.print(result)
end
ensure
Expand Down
8 changes: 6 additions & 2 deletions lib/modulr.rb
Expand Up @@ -17,15 +17,19 @@ module Modulr
PATH_TO_MODULR_JS = File.join(LIB_DIR, '..', 'assets', 'modulr.js')
PATH_TO_MODULR_SYNC_JS = File.join(LIB_DIR, '..', 'assets', 'modulr.sync.js')

def self.ize(input_filename, options = {})
def self.ize(*args)
options = args.last.is_a?(Hash) ? args.pop : {}
input_files = args

if options[:global]
collector = GlobalExportCollector.new(options)
elsif options[:sync]
collector = SyncCollector.new(options)
else
collector = Collector.new(options)
end
collector.parse_file(input_filename)

collector.parse_files(*input_files)
minify(collector.to_js, options[:minify])
end

Expand Down
62 changes: 53 additions & 9 deletions lib/modulr/collector.rb
@@ -1,27 +1,70 @@
module Modulr
class Collector
attr_reader :modules, :main
attr_reader :modules, :top_level_modules

def initialize(options = {})
@root = options[:root]
@lazy_eval = options[:lazy_eval]
@modules = []
@top_level_modules = []
end

def parse_file(path)
@src = File.read(path)
@root ||= File.dirname(path)
@main = JSModule.new(File.basename(path, '.js'), @root, path)
collect_dependencies(main)
parse_files(path)
end

def parse_files(*paths)
reset
paths.each do |path|
add_module_from_path(path)
end
end

def reset
modules.clear
top_level_modules.clear
end
private :reset

def module_from_path(path)
identifier = File.basename(path, '.js')
root = @root || File.dirname(path)
JSModule.new(identifier, root, path)
end
private :module_from_path

def add_module_from_path(path)
js_module = module_from_path(path)
top_level_modules << js_module
collect_dependencies(js_module)
js_module
end
private :add_module_from_path

def to_js(buffer = '')
buffer << File.read(PATH_TO_MODULR_JS)
buffer << "\n(function(require, module) {"
buffer << globals
buffer << "\n(function() {"
buffer << lib
buffer << transport
buffer << main.ensure
buffer << "})(modulr.require, modulr.require.main);\n"
buffer << requires
buffer << "})();\n"
end

def lib
src = File.read(PATH_TO_MODULR_JS)
"#{src}\nvar require = modulr.require, module = require.main;\n"
end
private :lib

def requires
top_level_modules.map { |m| m.ensure }.join("\n")
end
private :requires

def globals
''
end
private :globals

def transport
pairs = modules.map do |m|
Expand All @@ -34,6 +77,7 @@ def transport
end
"require.define({#{pairs.join(', ')}\n});"
end
private :transport

private
def collect_dependencies(js_module)
Expand Down
43 changes: 32 additions & 11 deletions lib/modulr/global_export_collector.rb
Expand Up @@ -6,27 +6,48 @@ def initialize(options = {})
super
end

def to_js(buffer = '')
buffer << "#{define_global} = (function() {\n"
buffer << File.read(PATH_TO_MODULR_SYNC_JS)
buffer << transport
buffer << "\n return require('#{main.id}');\n"
buffer << "})();\n"
def globals
if @global == true
top_level_modules.map { |m| define_global(m.id) }.join
else
define_global(@global)
end
end
private :globals

def define_global
if @global.include?('.')
props = @global.split('.')
def define_global(global)
if global.include?('.')
props = global.split('.')
str = props.shift
results = "var #{str};"
props.each do |prop|
results << "\n#{str} = #{str} || {};"
str << ".#{prop}"
end
"#{results}\n#{str}"
"#{results}\n#{str};\n"
else
"var #{global};\n"
end
end
private :define_global

def requires
if @global == true
top_level_modules.map do |m|
"\n #{m.id} = require('#{m.id}');"
end.join
else
"var #{@global}"
if top_level_modules.size == 1 #export to named global
"\n #{@global} = require('#{top_level_modules.first.id}');"
else
#export to props of named global
top_level_modules.inject("\n#{@global} = {};") do |str, m|
str << "\n #{@global}.#{m.id} = require('#{m.id}');"
end
end
end
end
private :requires

end
end
21 changes: 12 additions & 9 deletions lib/modulr/sync_collector.rb
@@ -1,16 +1,19 @@
module Modulr
class SyncCollector < Collector
def parse_file(path)
super(path)
modules << main unless modules.include?(main)
def add_module_from_path(path)
js_module = super(path)
modules << js_module unless modules.include?(js_module)
end

def to_js(buffer = '')
buffer << "(function() {\n"
buffer << File.read(PATH_TO_MODULR_SYNC_JS)
buffer << transport
buffer << "\nrequire('#{main.id}');\n"
buffer << "})();\n"
def lib
File.read(PATH_TO_MODULR_SYNC_JS)
end
private :lib

def requires
top_level_modules.map { |m| "\n require('#{m.id}');" }.join
end
private :requires

end
end
2 changes: 1 addition & 1 deletion modulr.gemspec
Expand Up @@ -9,7 +9,7 @@ Gem::Specification.new do |s|

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Tobie Langel"]
s.date = %q{2010-08-04}
s.date = %q{2010-10-31}
s.default_executable = %q{modulrize}
s.email = %q{tobie.langel@gmail.com}
s.executables = ["modulrize"]
Expand Down

0 comments on commit 71bc880

Please sign in to comment.