slinky 0.2.1 → 0.4.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/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile CHANGED
@@ -4,13 +4,18 @@ gem "eventmachine", ">= 0.12.0"
4
4
  gem "eventmachine_httpserver", ">= 0.2.0"
5
5
  gem "rainbow", ">= 1.1.1"
6
6
  gem "haml", ">= 3.0.0"
7
- #gem "sass", ">= 4.0.0"
7
+ gem "sass", ">= 3.1.1"
8
8
  gem "coffee-script", ">= 2.2.0"
9
+ gem "mime-types", ">= 1.16"
10
+ gem "yui-compressor", ">= 0.9.6"
9
11
 
10
12
  group :development do
11
- gem "bacon", ">= 0"
13
+ gem "rspec", "~> 2.3.0"
12
14
  gem "yard", "~> 0.6.0"
13
15
  gem "bundler", "~> 1.0.0"
14
16
  gem "jeweler", "~> 1.5.2"
15
- gem "rcov", ">= 0"
17
+ gem 'cover_me', '>= 1.0.0.rc6'
18
+ gem "fakefs"
19
+ gem "em-http-request"
20
+ # gem "em-synchrony", ">= 0"
16
21
  end
data/README.md CHANGED
@@ -1,9 +1,87 @@
1
1
  #Slinky
2
2
 
3
- Slinky is a static file server designed to make development of static
4
- web sites and applications simpler. Simply run slinky in the home
5
- directory of your app and it will serve while compiling things like
6
- SASS, HAML and CoffeeScript on the fly.
3
+ Slinky helps you write rich web applications using compiled web
4
+ languages like SASS, HAML and CoffeeScript. The slinky server
5
+ transparently compiles resources as they're requested, leaving you to
6
+ worry about your code, not how to compile it.
7
7
 
8
- To get it, just `gem install slinky`. Note that this is unstable, not well
9
- tested, and hardly feature-complete. It may, however, be useful.
8
+ Once your ready for production, the slinky builder will compile all of
9
+ your sources and concatenate and minify your javascript and css,
10
+ leaving you a directory that's ready to be pushed to your servers.
11
+
12
+ ## Quickstart
13
+
14
+ ```
15
+ $ gem install slinky
16
+ $ cd ~/my/awesome/project
17
+ $ slinky start
18
+ [hardcore web development action]
19
+ $ slinky build
20
+ $ scp -r build/ myserver.com/var/www/project
21
+ ````
22
+ ## But tell me more!
23
+
24
+ Slinky currently supports three languages for compilation, SASS/SCSS,
25
+ HAML and CoffeeScript, but it's simple to add support for others (and
26
+ please submit a pull request when you do!). Slinky also has a few
27
+ tricks of its own for managing the complexity of modern web
28
+ development.
29
+
30
+ ### Script & style management
31
+
32
+ Slinky can manage all of your javascript and css files if you want it
33
+ to, serving them up individually during development and concatenating
34
+ and minifying them for production. To support this, Slinky recognizes
35
+ `slinky_scripts` in your HTML/Haml files. For example, when Slinky
36
+ sees this:
37
+
38
+ ```haml
39
+ !!!5
40
+ %html
41
+ %head
42
+ slinky_scripts
43
+ slinky_styles
44
+ %body
45
+ %h1 Hello, world!
46
+ ```
47
+
48
+ it will compile the HAML to HTML and replace slinky_styles with the
49
+ appropriate HTML.
50
+
51
+ ### Specifying order
52
+
53
+ But what if your scripts or styles depend on being included in the
54
+ page in a particular order? For this, we need the `slinky_require`
55
+ directive.
56
+
57
+ For example, consider the case of two coffeescript files, A.coffee and
58
+ B.coffee. A includes a class definition that B depends upon, so we
59
+ want to make sure that A comes before B in the concatenation order. We
60
+ can solve this simply using `slinky_require(script)`
61
+
62
+ File A.coffee:
63
+
64
+ ```coffeescript
65
+ class A
66
+ hello: (thing) -> "Hello, " + thing
67
+ ```
68
+
69
+ File B.coffee:
70
+
71
+ ```coffeescript
72
+ slinky_require("A.coffee")
73
+ alert (new A).hello("world")
74
+ ```
75
+ We can also do this in CSS/SASS/SCSS:
76
+
77
+ ```sass
78
+ /* slinky_require("reset.css")
79
+ a
80
+ color: red
81
+ ```
82
+
83
+ ### And coming up next...
84
+
85
+ * Support for more languages
86
+ * Built in proxy-server to allow connections to web services
87
+ * More control over behavior
data/Rakefile CHANGED
@@ -22,20 +22,32 @@ Jeweler::Tasks.new do |gem|
22
22
  end
23
23
  Jeweler::RubygemsDotOrgTasks.new
24
24
 
25
- require 'rake/testtask'
26
- Rake::TestTask.new(:spec) do |spec|
27
- spec.libs << 'lib' << 'spec'
28
- spec.pattern = 'spec/**/*_spec.rb'
29
- spec.verbose = true
25
+ namespace :cover_me do
26
+ task :report do
27
+ require 'cover_me'
28
+ # CoverMe.config do |c|
29
+ # # where is your project's root:
30
+ # c.project.root = Dir.pwd
31
+
32
+ # # what files are you interested in coverage for:
33
+ # c.file_pattern = /(#{CoverMe.config.project.root}\/lib\/.+\.rb)/i
34
+ # end
35
+ CoverMe.complete!
36
+ end
30
37
  end
31
38
 
32
- require 'rcov/rcovtask'
33
- Rcov::RcovTask.new do |spec|
34
- spec.libs << 'spec'
35
- spec.pattern = 'spec/**/*_spec.rb'
36
- spec.verbose = true
39
+ # task :spec do
40
+ # Rake::Task['cover_me:report'].invoke
41
+ # end
42
+
43
+ require 'rspec/core'
44
+ require 'rspec/core/rake_task'
45
+ RSpec::Core::RakeTask.new(:spec) do |spec|
46
+ spec.pattern = FileList['spec/**/*_spec.rb']
37
47
  end
38
48
 
49
+
50
+
39
51
  task :default => :spec
40
52
 
41
53
  require 'yard'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.4.0
data/bin/slinky CHANGED
@@ -5,4 +5,4 @@ root = File.expand_path(File.dirname(__FILE__))
5
5
  #require "#{root}/../lib/slinky"
6
6
  require 'slinky'
7
7
 
8
- Slinky::Runner.run
8
+ Slinky::Runner.new(ARGV).run
@@ -0,0 +1,8 @@
1
+ module Slinky
2
+ class Builder
3
+ def self.build dir, build_dir
4
+ manifest = Manifest.new(dir, :build_to => build_dir, :devel => false)
5
+ manifest.build
6
+ end
7
+ end
8
+ end
@@ -2,62 +2,80 @@ module Slinky
2
2
  # Stores information about compiled files, including location,
3
3
  # source file and last modified time
4
4
  class CompiledFile
5
- attr_reader :source, :last_compiled
6
-
5
+ attr_accessor :source, :print_name, :output_path
6
+ attr_reader :last_compiled, :output_ext
7
+
7
8
  # Creates a new CompiledFile, compiling the provided source file
8
9
  # with the provided compiler class.
9
10
  def initialize source, compiler, output_ext
11
+ super source
10
12
  @source = source
11
13
  @compiler = compiler
12
14
  @last_compiled = Time.new(0)
13
15
  @output_ext = output_ext
14
16
  end
15
17
 
18
+ def build path
19
+ compiler_compile path, EM::DefaultDeferrable
20
+ end
21
+
16
22
  # Compiles the source file to a temporary location
17
23
  def compile &cb
18
- path = @path || tmp_path
24
+ path = @output_path || tmp_path
19
25
  @last_compiled = Time.now
20
26
  if @compiler.respond_to? :compile
21
27
  compiler_compile path, cb
22
28
  else
23
- compiler_command path, cb
29
+ compile_failed "invalid compiler"
30
+ cb.call @output_path, nil, nil, "invalid compiler"
31
+ # compiler_command path, cb
24
32
  end
25
33
  end
26
34
 
27
35
  def compiler_compile path, cb
28
36
  begin
29
- out = @compiler.compile @source
37
+ out = File.open @source do |f|
38
+ @compiler.compile f.read, @source
39
+ end
40
+
30
41
  compile_succeeded
31
- @path = path
32
42
  File.open(path, "w+") do |f|
33
43
  f.write out
34
44
  end
35
- rescue
45
+ rescue Exception
36
46
  compile_failed $!
47
+ path = nil
37
48
  end
38
- cb.call @path, nil, nil, $!
49
+ cb.call((path ? path.to_s : nil), nil, nil, $!)
39
50
  end
40
51
 
41
- def command path, cb
42
- command = @compiler.command @source, path
52
+ # def compiler_command path, cb
53
+ # #NOTE: This currently won't strip out compiler directives, so
54
+ # #use at own risk. Ideally all compilers would have ruby version
55
+ # #so we don't have to use this
56
+ # command = @compiler.command @source, path
43
57
 
44
- EM.system3 command do |stdout, stderr, status|
45
- if status.exitstatus != 0
46
- compile_failed stderr.strip
47
- else
48
- compile_succeeded
49
- @path = path
50
- end
51
- cb.call(@path, status, stdout, stderr)
52
- end
58
+ # EM.system3 command do |stdout, stderr, status|
59
+ # if status.exitstatus != 0
60
+ # compile_failed stderr.strip
61
+ # else
62
+ # compile_succeeded
63
+ # @output_path = path
64
+ # end
65
+ # cb.call(@output_path, status, stdout, stderr)
66
+ # end
67
+ # end
68
+
69
+ def name
70
+ @print_name || @source
53
71
  end
54
72
 
55
73
  def compile_succeeded
56
- puts "Compiled #{@source}".foreground(:green)
74
+ $stdout.puts "Compiled #{name}".foreground(:green)
57
75
  end
58
76
 
59
77
  def compile_failed e
60
- $stderr.write "Failed on #{@source}: #{e}\n".foreground(:red)
78
+ $stderr.puts "Failed on #{name}: #{e}".foreground(:red)
61
79
  end
62
80
 
63
81
  # Calls the supplied callback with the path of the compiled file,
@@ -66,7 +84,7 @@ module Slinky
66
84
  if needs_update?
67
85
  compile &cb
68
86
  else
69
- cb.call @path, nil, nil, nil
87
+ cb.call @output_path, nil, nil, nil
70
88
  end
71
89
  end
72
90
 
@@ -74,7 +92,7 @@ module Slinky
74
92
  # compiled.
75
93
  def needs_update?
76
94
  return true if @compiler.to_s.match "SassCompiler"
77
- File.new(source).mtime > @last_compiled
95
+ File.new(source).mtime > @last_compiled rescue true
78
96
  end
79
97
 
80
98
  private
@@ -2,12 +2,11 @@ require 'coffee-script'
2
2
 
3
3
  module Slinky
4
4
  module CoffeeCompiler
5
- Server.register_compiler self,
5
+ Compilers.register_compiler self,
6
6
  :inputs => ["coffee"],
7
7
  :outputs => ["js"]
8
8
 
9
- def CoffeeCompiler::compile file
10
- s = File.read(file)
9
+ def CoffeeCompiler::compile s, file
11
10
  CoffeeScript::compile(s)
12
11
  end
13
12
  end
@@ -2,14 +2,20 @@ require 'haml'
2
2
 
3
3
  module Slinky
4
4
  module HamlCompiler
5
- Server.register_compiler self,
5
+ Compilers.register_compiler self,
6
6
  :inputs => ["haml"],
7
7
  :outputs => ["html"]
8
8
 
9
- def HamlCompiler::compile file
10
- s = File.read(file)
9
+ def HamlCompiler::compile s, file
11
10
  haml_engine = Haml::Engine.new(s)
12
11
  haml_engine.render
13
- end
12
+ end
13
+
14
+ # escape should return a string that can be inserted into the
15
+ # document in such a way that after compilation the string will be
16
+ # intact in the final output.
17
+ def HamlCompiler::escape s
18
+ s
19
+ end
14
20
  end
15
21
  end
@@ -2,12 +2,11 @@ require 'sass'
2
2
 
3
3
  module Slinky
4
4
  module SassCompiler
5
- Server.register_compiler self,
5
+ Compilers.register_compiler self,
6
6
  :inputs => ["sass", "scss"],
7
7
  :outputs => ["css"]
8
8
 
9
- def SassCompiler::compile file
10
- s = File.read(file)
9
+ def SassCompiler::compile s, file
11
10
  sass_engine = Sass::Engine.new(s, :load_paths => [File.dirname(file)])
12
11
  sass_engine.render
13
12
  end
@@ -0,0 +1,72 @@
1
+ module Slinky
2
+ EXTENSION_REGEX = /(.+)\.(\w+)/
3
+
4
+ class Compilers
5
+ @compilers = []
6
+ @compilers_by_ext = {}
7
+ @compilers_by_input = {}
8
+
9
+ class << self
10
+ def register_compiler klass, options
11
+ options[:klass] = klass
12
+ @compilers << options
13
+ options[:outputs].each do |output|
14
+ @compilers_by_ext[output] ||= []
15
+ @compilers_by_ext[output] << options
16
+ end
17
+ options[:inputs].each do |input|
18
+ @compilers_by_input[input] = options
19
+ end
20
+ end
21
+
22
+ # Produces a CompiledFile for an input file if the file needs to
23
+ # be compiled, or nil otherwise. Note that path is the path of
24
+ # the compiled file, so script.js not script.coffee.
25
+ def cfile_for_request path
26
+ _, file, extension = path.match(EXTENSION_REGEX).to_a
27
+
28
+ compilers = @compilers_by_ext
29
+
30
+ # if there's a file extension and we have a compiler that
31
+ # outputs that kind of file, look for an input with the same
32
+ # name and an extension in our list
33
+ if extension && extension != "" && compilers[extension]
34
+ files_by_ext = {}
35
+ # find possible source files
36
+ Dir.glob("#{file}.*").each do |f|
37
+ _, _, ext = f.match(EXTENSION_REGEX).to_a
38
+ files_by_ext[ext] = f
39
+ end
40
+
41
+ cfile = nil
42
+ # find a compiler that outputs the request kind of file and
43
+ # which has an input file type that exists on the file system
44
+ compilers[extension].each do |c|
45
+ c[:inputs].each do |i|
46
+ if files_by_ext[i]
47
+ cfile = CompiledFile.new files_by_ext[i], c[:klass], extension
48
+ break
49
+ end
50
+ end
51
+ break if cfile
52
+ end
53
+ cfile
54
+ else
55
+ nil
56
+ end
57
+ end
58
+
59
+ # Like cfile_for_request, but for the actual file to be compiled
60
+ # (so script.coffee, not script.js).
61
+ def cfile_for_file path
62
+ _, file, ext = path.match(EXTENSION_REGEX).to_a
63
+
64
+ if ext && ext != "" && compiler = @compilers_by_input[ext]
65
+ CompiledFile.new path, compiler[:klass], compiler[:outputs].first
66
+ else
67
+ nil
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end