architecture-js 0.0.0 → 0.1.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.
@@ -0,0 +1,80 @@
1
+ module ArchitectureJS
2
+ module Command
3
+ def watch(path = nil)
4
+ require "fssm"
5
+
6
+ path ||= File.expand_path(Dir.getwd)
7
+
8
+ puts ArchitectureJS::Notification.log "ArchitectureJS are watching for changes. Press Ctrl-C to stop."
9
+ project = ArchitectureJS::Project.init_with_config
10
+ project.update
11
+ watch_hash = Hash.new
12
+
13
+ project.watch_directories.each do |dir|
14
+ watch_hash["#{path}/#{dir}"] = "**/*.js"
15
+ end
16
+
17
+ watch_hash[path] = "**/*.conf"
18
+ watch_hash["#{ArchitectureJS::BASE_DIR}/repository"] = "**/*.js"
19
+
20
+ FSSM.monitor do
21
+ watch_hash.each do |dir, g|
22
+ path "#{dir}" do
23
+ glob g
24
+
25
+ update do |base, relative|
26
+ puts ArchitectureJS::Notification.event "change detected in #{relative}"
27
+ project.config.read if relative.match(/conf$/)
28
+ project.update
29
+ end
30
+
31
+ create do |base, relative|
32
+ puts ArchitectureJS::Notification.event "#{relative} created"
33
+ project.update
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end # watch
39
+
40
+ def create(config = nil)
41
+ settings = {
42
+ name: nil,
43
+ root: File.expand_path(Dir.getwd)
44
+ }
45
+
46
+ settings.merge!(config) unless config.nil?
47
+
48
+ raise 'you must specify a project name: architect create ProjectName' if settings[:name].nil?
49
+
50
+ project = ArchitectureJS::Project.new({ name: settings[:name] }, settings[:root])# TODO add settings[:framework]
51
+ project.create
52
+ end
53
+
54
+ def compile(options = nil)
55
+ settings = {
56
+ force_compress: false,
57
+ path: File.expand_path(Dir.getwd)
58
+ }
59
+
60
+ settings.merge!(options) if options
61
+
62
+ project = ArchitectureJS::create_project_from_config(settings[:path])
63
+ project.config[:output] = 'compressed' if settings[:force_compress]
64
+ project.update
65
+ end
66
+
67
+ # TODO make generate generic to accept a type, look up in either local templates or master, and pass it options and flags parsed for use in erb files
68
+ def generate(config)
69
+ conf_path = "#{config[:project].root}/ninjs.conf"
70
+ raise "ninjs.conf was not located in #{conf_path}" unless File.exists? conf_path
71
+ generator = ArchitectureJS::Generator.new(config)
72
+ generator.generate
73
+ end
74
+
75
+ module_function :create,
76
+ :watch,
77
+ :compile,
78
+ :generate
79
+ end
80
+ end
@@ -0,0 +1,18 @@
1
+ begin
2
+ require 'yaml'
3
+ require 'jsmin'
4
+ require 'tempfile'
5
+ require 'sprockets'
6
+ require 'fileutils'
7
+ require 'time'
8
+ require 'erb'
9
+ rescue LoadError
10
+ require 'rubygems'
11
+ require 'yaml'
12
+ require 'jsmin'
13
+ require 'tempfile'
14
+ require 'sprockets'
15
+ require 'fileutils'
16
+ require 'time'
17
+ require 'erb'
18
+ end
@@ -0,0 +1,44 @@
1
+ module ArchitectureJS
2
+ class Generator
3
+
4
+ attr_reader :template_paths,
5
+ :templates,
6
+ :project
7
+
8
+ def initialize(project)
9
+ @project = project
10
+ @template_paths = @project.template_directories
11
+ @templates = Hash.new
12
+ find_templates @template_paths
13
+ #@template_dir = template_dir
14
+ #@template_files = Dir.entries(template_dir).reject {|file| file.match /^\./ }
15
+ #@templates = Hash.new
16
+ #@template_files.each do |file|
17
+ # name = file.gsub /\.\w+$/, ''
18
+ # @templates[name] = ERB.new(File.read(File.expand_path(file, @template_dir)))
19
+ #end
20
+ end
21
+
22
+ def find_templates(paths)
23
+ paths.each do |path|
24
+ Dir["#{path}/*_template*"].each do |file|
25
+ template_name = get_template_name file
26
+ @templates[template_name] = get_template(file)
27
+ end
28
+ end
29
+ end
30
+
31
+ def get_template_name(file)
32
+ file.split(/\/|\\/).last.gsub(/_template\.\w*/, '')
33
+ end
34
+
35
+ def get_template(file)
36
+ ERB.new File.read(file)
37
+ end
38
+
39
+ def render_template(template, options = nil)
40
+ project = @project
41
+ @templates[template].result(binding)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ module ArchitectureJS
2
+ module Helpers
3
+
4
+ def get_file_name(module_path)
5
+ module_path = module_path.split(/[\\\/]/).last
6
+ split = module_path.split(/[\.\-\s]/)
7
+ module_filename = String.new
8
+ split.each do |piece|
9
+ module_filename << piece unless piece.match(/^module$|^js$/i)
10
+ end
11
+ module_filename
12
+ end
13
+
14
+ def array_to_yml(array)
15
+ yml = array.empty? ? '[]' : %Q{['#{array.join("', '")}']}
16
+ end
17
+
18
+ def symbolize_keys(hash)
19
+ symbolized_hash = Hash.new
20
+ hash.each do |key, value|
21
+ symbolized_hash[key.to_sym] = value
22
+ end
23
+ symbolized_hash
24
+ end
25
+
26
+ module_function :get_file_name,
27
+ :array_to_yml,
28
+ :symbolize_keys
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ module ArchitectureJS
2
+ class Notification
3
+
4
+ win_platform = !![
5
+ /bccwin/i,
6
+ /djgpp/i,
7
+ /mingw/i,
8
+ /mswin/i,
9
+ /wince/i,
10
+ ].find{ |r| RUBY_PLATFORM =~ r }
11
+
12
+ @@indicators = {
13
+ none: "",
14
+ log: "\e[32m>>>\e[0m ",
15
+ event: "\e[33m<<<\e[0m ",
16
+ added: "\e[32m+++\e[0m ",
17
+ error: "\e[0;31m!!!\e[0m "
18
+ }
19
+
20
+ @@indicators.merge!({
21
+ none: "",
22
+ log: ">>>",
23
+ event: "<<<",
24
+ added: "+++",
25
+ error: "!!!"
26
+ }) if win_platform
27
+
28
+ def self.notify(type, message)
29
+ raise "There is no #{type} indicator" unless @@indicators[type]
30
+ "#{@@indicators[type]}#{message}"
31
+ end
32
+
33
+ def self.notice(message)
34
+ self.notify :none, message
35
+ end
36
+
37
+ def self.log(message)
38
+ self.notify :log, message
39
+ end
40
+
41
+ def self.event(message)
42
+ self.notify :event, message
43
+ end
44
+
45
+ def self.added(message)
46
+ self.notify :added, message
47
+ end
48
+
49
+ def self.error(message)
50
+ self.notify :error, message
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,138 @@
1
+ module ArchitectureJS
2
+ class Project # TODO make generator belong to project to have default templates hooked up to generator
3
+ attr_reader :root,
4
+ :src_files,
5
+ :framework,
6
+ :config_name,
7
+ :watch_directories,
8
+ :directories,
9
+ :template_directories,
10
+ :generator
11
+
12
+ attr_accessor :config
13
+
14
+ # this line adds the default framework to ArchitectureJS
15
+ ArchitectureJS::register_framework 'none', self
16
+
17
+ def initialize(config, root = nil)
18
+ raise "#{self.class}.new({ name: 'myapp' }, options): config[:name] is undefined" unless config[:name]
19
+ @config_file = "#{config[:name].downcase}.architecture"
20
+ root ||= Dir.getwd
21
+ @root = File.expand_path(root)
22
+ @template_directories = ["#{ArchitectureJS::BASE_DIR}/templates", "#{@root}/templates"]
23
+ @directories = ['lib', 'src']
24
+ @watch_directories = ['src']
25
+ @src_files = Array.new
26
+ @config = {
27
+ framework: 'none',
28
+ src_dir: 'src',
29
+ build_dir: 'lib',
30
+ asset_root: '../',
31
+ output: 'compressed'
32
+ }
33
+ @config.merge! config unless config.nil?
34
+ @generator = ArchitectureJS::Generator.new self
35
+ end
36
+
37
+ def read_config
38
+ config = YAML.load_file("#{@root}/#{@config_file}")
39
+ assign_config_variables config
40
+ end
41
+
42
+ def assign_config_variables(config)
43
+ config.each do |key, value|
44
+ @config[key.to_sym] = value
45
+ end
46
+ end
47
+
48
+ def create
49
+ puts ArchitectureJS::Notification.notice "Creating the #{@config[:name]} project in #{@root}"
50
+ create_project_scaffold
51
+ write_config
52
+ end
53
+
54
+ def create_project_scaffold
55
+ Dir.mkdir "#{@root}" unless File.exists? "#{@root}"
56
+
57
+ @directories.each do |dir|
58
+ puts ArchitectureJS::Notification.added "#{dir} created" unless File.exists? "#{@root}/#{dir}"
59
+ Dir.mkdir "#{@root}/#{dir}" unless File.exists? "#{@root}/#{dir}"
60
+ end
61
+ end
62
+
63
+ def write_config
64
+ File.open("#{@root}/#{@config_file}", "w+") do |conf_file|
65
+ @config.each do |key, value|
66
+ conf_file << "#{key}: #{ArchitectureJS::Helpers.array_to_yml value}\n" if value.is_a? Array
67
+ conf_file << "#{key}: #{value}\n" if value.is_a? String
68
+ end
69
+ end
70
+
71
+ puts ArchitectureJS::Notification.added "#{@config_file} created"
72
+ end
73
+
74
+ def update
75
+ get_src_files
76
+ compile_src_files
77
+ compress_application if @output == 'compressed'
78
+ puts ArchitectureJS::Notification.log "application updated" unless @errors
79
+ @errors = false
80
+ end
81
+
82
+ def get_src_files
83
+ [*@config[:src_dir]].each do |directory|
84
+ add_src_files_to_project File.expand_path(directory, @root)
85
+ end
86
+ end
87
+
88
+ def add_src_files_to_project(directory)
89
+ puts '-------------------'
90
+ puts directory
91
+ puts '-------------------'
92
+ Dir["#{directory}/*.js"].each do |file|
93
+ src_filename = file.gsub(directory, '')
94
+ @src_files << "#{directory}#{src_filename}" unless src_filename.match(/^\/_/)
95
+ end
96
+ end
97
+
98
+ def compile_src_files
99
+ @src_files.each do |file_path|
100
+ file_name = ArchitectureJS::Helpers.get_file_name file_path
101
+ compile_src_file file_path, file_name
102
+ end
103
+ end
104
+
105
+ def compile_src_file(file_path, file_name)
106
+ sprockets = Sprockets::Secretary.new(
107
+ :root => "#{ArchitectureJS::BASE_DIR}",
108
+ :asset_root => File.expand_path(@config[:asset_root], @root),
109
+ :load_path => ["repository"],
110
+ source_files: ["#{file_path}"]
111
+ )
112
+
113
+ compiled_file = sprockets.concatenation
114
+ message = File.exists?("#{@root}/#{@config[:build_dir]}/#{file_name}.js") ? "\e[32m>>>\e[0m #{@config[:build_dir]}/#{file_name}.js updated" : "\e[32m>>>\e[0m #{@config[:build_dir]}/#{file_name}.js created"
115
+ compiled_file.save_to "#{@root}/#{@config[:build_dir]}/#{file_name}.js"
116
+ sprockets.install_assets
117
+
118
+ rescue Exception => error
119
+ @errors = true
120
+ puts ArchitectureJS::Notification.error "Sprockets error: #{error.message}"
121
+ end
122
+
123
+ def compress_application
124
+ app_root = File.expand_path "#{@config[:build_dir]}"
125
+ src_files = Dir.entries(app_root)
126
+ src_files.reject! { |file| file =~ /^\./ }
127
+
128
+ src_files.each do |module_file|
129
+ full_path = "#{app_root}/#{module_file}"
130
+ uncompressed = File.open(full_path, "r").read
131
+ File.open(full_path, "w+") do |module_file|
132
+ module_file << JSMin.minify(uncompressed)
133
+ end
134
+ end
135
+ end
136
+
137
+ end # class Project
138
+ end # module ArchitectureJS
@@ -1,7 +1,54 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require "spec_helper"
2
2
 
3
- describe "Foo" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
3
+ describe ArchitectureJS do
4
+ it 'should have a BASE_DIR constant' do
5
+ ArchitectureJS::BASE_DIR.should_not be_nil
6
6
  end
7
+
8
+ it 'should have a LIB_DIR constant' do
9
+ ArchitectureJS::LIB_DIR.should_not be_nil
10
+ end
11
+
12
+ it 'should have a ROOT_DIR' do
13
+ ArchitectureJS::ROOT_DIR.should_not be_nil
14
+ end
15
+
16
+ it 'should have the correct VERSION' do
17
+ version = File.open("#{ArchitectureJS::BASE_DIR}/VERSION").read
18
+ ArchitectureJS::VERSION.should === version
19
+ end
20
+
21
+ it 'should have a FRAMEWORKS constant' do
22
+ ArchitectureJS::FRAMEWORKS.should_not be_nil
23
+ end
24
+
25
+ context "Instantiation with a config file" do
26
+
27
+ before :each do
28
+ FileUtils.mkdir("#{TMP_DIR}")
29
+ FileUtils.cp "#{FIXTURES}/existing.architecture", "#{TMP_DIR}/myapp.architecture"
30
+ suppress_output { @project = ArchitectureJS::create_project_from_config(TMP_DIR) }
31
+ end
32
+
33
+ after :each do
34
+ FileUtils.rm_rf "#{TMP_DIR}" if File.exists? "#{TMP_DIR}"
35
+ end
36
+
37
+ it "should raise an error if there is no .architecture file" do
38
+ FileUtils.rm_rf "#{TMP_DIR}/myapp.architecture"
39
+ lambda { ArchitectureJS::create_project_from_config TMP_DIR }.should raise_error
40
+ end
41
+
42
+ it 'should set defaults from config file' do
43
+ @project.config.should == {
44
+ framework: 'none',
45
+ src_dir: 'source',
46
+ build_dir: 'dest',
47
+ asset_root: '../',
48
+ output: 'compressed',
49
+ name: 'test',
50
+ }
51
+ end
52
+
53
+ end # Instantiation with an existing config file
7
54
  end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'CLI' do
4
+ before :each do
5
+ @bin = "#{ArchitectureJS::BASE_DIR}/bin/architect"
6
+ FileUtils.mkdir "#{TMP_DIR}" unless File.exists? "#{TMP_DIR}"
7
+ suppress_output { %x(cd #{TMP_DIR}; #{@bin} create myapp) }
8
+ FileUtils.cp "#{FIXTURES}/lib1.js", "#{TMP_DIR}/lib/lib1.js"
9
+ FileUtils.cp "#{FIXTURES}/lib2.js", "#{TMP_DIR}/lib/lib2.js"
10
+ FileUtils.cp "#{FIXTURES}/src_file.js", "#{TMP_DIR}/src/myapp.js"
11
+ end
12
+
13
+ after :each do
14
+ FileUtils.rm_rf "#{TMP_DIR}" if File.exists? "#{TMP_DIR}"
15
+ end
16
+
17
+ it 'should create a new application' do
18
+ "#{TMP_DIR}/myapp.architecture".should be_same_file_as "#{FIXTURES}/myapp.architecture"
19
+ File.directory? "#{TMP_DIR}/lib"
20
+ File.directory? "#{TMP_DIR}/src"
21
+ end
22
+
23
+ it 'should create a new application in a subdirectory' do
24
+ suppress_output { %x(cd #{TMP_DIR}; #{@bin} create myapp sub) }
25
+ "#{TMP_DIR}/sub/myapp.architecture".should be_same_file_as "#{FIXTURES}/myapp.architecture"
26
+ File.directory? "#{TMP_DIR}/sub/lib"
27
+ File.directory? "#{TMP_DIR}/sub/src"
28
+ File.exists? "#{TMP_DIR}/sub/myapp.js"
29
+ FileUtils.rm_rf "#{TMP_DIR}/sub"
30
+ end
31
+
32
+ it 'should compile the application' do
33
+ suppress_output { %x(cd #{TMP_DIR}; #{@bin} compile) }
34
+ File.exists?("#{TMP_DIR}/lib/myapp.js").should be_true
35
+ "#{TMP_DIR}/lib/myapp.js".should be_same_file_as "#{FIXTURES}/compiled_src.js"
36
+ end
37
+
38
+ end