tipsy 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/Gemfile +9 -0
  2. data/README.md +2 -2
  3. data/Rakefile +10 -0
  4. data/bin/tipsy +16 -5
  5. data/lib/tipsy.rb +26 -14
  6. data/lib/tipsy/application.rb +14 -16
  7. data/lib/tipsy/builder.rb +17 -4
  8. data/lib/tipsy/builders/base.rb +64 -0
  9. data/lib/tipsy/builders/export.rb +16 -0
  10. data/lib/tipsy/builders/project.rb +40 -0
  11. data/lib/tipsy/builders/remote.rb +14 -0
  12. data/lib/tipsy/compressors/css.rb +11 -0
  13. data/lib/tipsy/compressors/javascript.rb +25 -0
  14. data/lib/tipsy/helpers.rb +24 -1
  15. data/lib/tipsy/helpers/asset_paths.rb +19 -0
  16. data/lib/tipsy/helpers/asset_tags.rb +32 -0
  17. data/lib/tipsy/helpers/capture.rb +33 -0
  18. data/lib/tipsy/helpers/sass.rb +40 -0
  19. data/lib/tipsy/helpers/tag.rb +12 -0
  20. data/lib/tipsy/logger.rb +54 -3
  21. data/lib/tipsy/project/Gemfile +8 -0
  22. data/lib/tipsy/project/config.erb +5 -2
  23. data/lib/tipsy/sass/template.rb +137 -0
  24. data/lib/tipsy/server.rb +50 -7
  25. data/lib/tipsy/version.rb +1 -1
  26. data/lib/tipsy/view.rb +24 -10
  27. data/test/fixtures/about.html +1 -0
  28. data/test/fixtures/contact.html +1 -0
  29. data/test/fixtures/index.html +1 -0
  30. data/test/functional/page_test.rb +33 -0
  31. data/test/root/{assets → development/assets}/javascripts/test.js +0 -0
  32. data/test/root/{assets → development/assets}/stylesheets/screen.css.scss +0 -0
  33. data/test/root/{config.rb → development/config.rb} +0 -0
  34. data/test/root/{views → development/views}/_layout.html.erb +0 -0
  35. data/test/root/{views → development/views}/index.html.erb +0 -0
  36. data/test/root/test/assets/javascripts/test.js +0 -0
  37. data/test/root/test/assets/stylesheets/screen.css.scss +3 -0
  38. data/test/root/test/config.rb +6 -0
  39. data/test/root/test/views/_layout.html.erb +1 -0
  40. data/test/root/test/views/about/index.html +1 -0
  41. data/test/root/test/views/contact.html +1 -0
  42. data/test/root/test/views/index.html.erb +1 -0
  43. data/test/test_helper.rb +33 -0
  44. data/test/unit/helpers/asset_paths_test.rb +14 -0
  45. data/test/unit/helpers_test.rb +22 -0
  46. data/test/unit/server_test.rb +1 -0
  47. data/tipsy.gemspec +5 -4
  48. metadata +83 -35
  49. data/config.ru +0 -26
  50. data/lib/tipsy/generator.rb +0 -53
data/Gemfile CHANGED
@@ -3,3 +3,12 @@ gemspec
3
3
 
4
4
  gem 'facades', :path => '/_Work/gems/facades'
5
5
  gem 'thin'
6
+
7
+ group :test do
8
+ gem 'jnunemaker-matchy', '~> 0.4.0', :require => 'matchy'
9
+ gem 'shoulda', '~> 2.11'
10
+ gem 'mocha', '~> 0.9.12'
11
+ gem 'rack-test'
12
+ gem 'turn'
13
+ gem 'minitest'
14
+ end
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
- = Tipsy
1
+ # Tipsy
2
2
 
3
3
  Tipsy is a small Rack-based server inspired by gems like StaticMatic and Serve. Its purpose is to aid development of static sites by providing
4
4
  Rails-esque style templating and helpers. Various template types are supported via the Tilt gem, and assets are served via Sprockets, essentially giving you
5
5
  a miniture Rails "view-only" environment.
6
6
 
7
- === Notes
7
+ ### Notes
8
8
 
9
9
  Tipsy was developed for personal/internal use but feature/pull requests are gladly accepted. It is not designed to function in any kind of production
10
10
  environment. When ready to upload files to a production environment, build the project and upload the result.
data/Rakefile CHANGED
@@ -1 +1,11 @@
1
+ require 'rake'
1
2
  require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/*_test.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
data/bin/tipsy CHANGED
@@ -1,10 +1,21 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
4
- require 'rubygems'
5
- require 'bundler'
6
- Bundler.require
3
+ libdir = File.dirname(__FILE__) + '/../lib'
4
+ if File.file?(libdir + '/tipsy/version.rb')
5
+ $LOAD_PATH.unshift(libdir)
6
+ end
7
+
8
+ begin
9
+ require 'tipsy'
10
+ rescue LoadError
11
+ require 'rubygems'
12
+ retry
13
+ end
14
+
15
+ if File.exists?(File.join(File.expand_path('.'), 'Gemfile'))
16
+ require 'bundler/setup'
17
+ Bundler.require(:default)
18
+ end
7
19
 
8
- require 'tipsy'
9
20
  Tipsy.root = File.expand_path('.')
10
21
  Tipsy.run_command(ARGV, STDIN)
data/lib/tipsy.rb CHANGED
@@ -8,17 +8,29 @@ module Tipsy
8
8
  autoload :Application, 'tipsy/application'
9
9
  autoload :Server, 'tipsy/server'
10
10
  autoload :Responder, 'tipsy/handler'
11
+ autoload :Helpers, 'tipsy/helpers'
12
+ autoload :Builder, 'tipsy/builder'
13
+ autoload :Logger, 'tipsy/logger'
11
14
  autoload :View, 'tipsy/view'
12
- autoload :Helpers, 'tipsy/helpers'
13
15
 
14
- autoload :Builder, 'tipsy/builder'
15
- autoload :Generator, 'tipsy/generator'
16
-
16
+ module Compressors
17
+ autoload :CssCompressor, 'tipsy/compressors/css'
18
+ autoload :JavascriptCompressor, 'tipsy/compressors/javascript'
19
+ end
20
+
21
+ module Sass
22
+ autoload :Template, 'tipsy/sass/template'
23
+ end
24
+
17
25
  mattr_accessor :root
18
26
  mattr_accessor :logger
19
27
  mattr_accessor :env
20
28
  mattr_accessor :sprockets
21
29
  mattr_accessor :compass
30
+
31
+ def self.logger
32
+ @logger ||= Tipsy::Logger.new($stdout)
33
+ end
22
34
 
23
35
  def self.run_command(args, stdin)
24
36
  args = [args].flatten
@@ -31,20 +43,20 @@ module Tipsy
31
43
  end
32
44
 
33
45
  args.shift
34
-
35
- options.port = 4000
36
- options.host = '0.0.0.0'
37
- options.assets = []
38
- options.build_path = File.join(Tipsy.root, 'build')
39
- options.public_path = File.join(Tipsy.root, 'public')
40
- options.asset_path = File.join(options.public_path, 'assets')
41
-
42
- parse_options!
46
+ parse_options!
43
47
  Tipsy::Application.send(:"#{to_run}", *args)
48
+
44
49
  end
45
50
 
46
51
  def self.options
47
- @@options ||= OpenStruct.new
52
+ @@options ||= OpenStruct.new({
53
+ :port => 4000,
54
+ :host => '0.0.0.0',
55
+ :assets => OpenStruct.new({ :paths => [], :precompile => [] }),
56
+ :build_path => File.join(Tipsy.root, 'build'),
57
+ :public_path => File.join(Tipsy.root, 'public'),
58
+ :asset_path => File.join(Tipsy.root, 'public', 'assets')
59
+ })
48
60
  end
49
61
 
50
62
  private
@@ -1,6 +1,9 @@
1
1
  require 'rack'
2
- require 'tipsy/server'
3
2
 
3
+ ##
4
+ # Base class for all applications. Handles configuration of options,
5
+ # and processing of command line arguments.
6
+ #
4
7
  module Tipsy
5
8
  class Application
6
9
 
@@ -9,11 +12,15 @@ module Tipsy
9
12
 
10
13
  def self.create(name = nil)
11
14
  raise "Missing project name for 'tipsy new'" unless name
12
- Tipsy::Generator.create_project!(name)
15
+ Tipsy::Builder.build!(:project, name)
13
16
  end
14
17
 
15
18
  def self.build
16
- Tipsy::Builder.new(self.config.build_path)
19
+ Tipsy::Builder.build!(:export)
20
+ end
21
+
22
+ def self.deploy
23
+ Tipsy::Builder.build!(:remote)
17
24
  end
18
25
 
19
26
  def self.initialize!
@@ -31,19 +38,10 @@ module Tipsy
31
38
  end
32
39
 
33
40
  def initialize
41
+ require 'tipsy/helpers/sass'
42
+ @app = Tipsy::Server.init!
34
43
 
35
- @app = Rack::Builder.new {
36
- use Rack::CommonLogger
37
- use Rack::ShowStatus
38
- use Rack::ShowExceptions
39
- use Tipsy::StaticFile, :root => Tipsy.options.public_path, :urls => %w[/]
40
- run Rack::Cascade.new([
41
- Rack::URLMap.new({ "/#{File.basename(Tipsy.options.asset_path)}" => Tipsy::AssetHandler.new }),
42
- Tipsy::Server.new
43
- ])
44
- }
45
-
46
- puts "Tipsy #{Tipsy::VERSION} running on #{config.address}:#{config.port}"
44
+ Tipsy.logger.info("Tipsy #{Tipsy::VERSION} running on #{config.address}:#{config.port}")
47
45
 
48
46
  begin run_thin
49
47
  rescue LoadError
@@ -79,7 +77,7 @@ module Tipsy
79
77
  def run_webrick
80
78
  handler = Rack::Handler.get('webrick')
81
79
  handler.run app, server_opts do |server|
82
- puts "Running Tipsy with Webrick. To use Mongrel or Thin, add them to your Gemfile"
80
+ puts "Running Tipsy with Webrick. To use Mongrel or Thin (recommended), add them to your Gemfile"
83
81
  trap("INT"){ server.shutdown }
84
82
  end
85
83
  end
data/lib/tipsy/builder.rb CHANGED
@@ -1,12 +1,25 @@
1
1
  require 'active_support/inflector'
2
2
 
3
+ ##
4
+ # Handles building source files into a final project, for
5
+ # either deployment or output to a directory
6
+ #
3
7
  module Tipsy
4
- class Builder
8
+ module Builder
5
9
 
6
- attr_reader :build_path
10
+ autoload :Base, 'tipsy/builders/base'
11
+ autoload :ProjectBuilder, 'tipsy/builders/project'
12
+ autoload :ExportBuilder, 'tipsy/builders/local'
13
+ autoload :RemoteBuilder, 'tipsy/builders/remote'
7
14
 
8
- def initialize(path)
9
- @build_path = path
15
+ def self.build!(type = :project, *args)
16
+ handler = case type
17
+ when :project then ProjectBuilder.new(*args)
18
+ when :export then ExportBuilder.new(*args)
19
+ when :remote then RemoteBuilder.new(*args)
20
+ else raise 'No builder specified'
21
+ end
22
+ handler.build!
10
23
  end
11
24
 
12
25
  end
@@ -0,0 +1,64 @@
1
+ module Tipsy
2
+ module Builder
3
+ class Base
4
+ attr_reader :source_path, :dest_path
5
+
6
+ def excludes
7
+ @excludes ||= ['.git', '.gitignore', '.sass-cache', 'config.erb', '*.rb', '.', '..']
8
+ end
9
+
10
+ def build!
11
+ process_location(source_path, dest_path)
12
+ end
13
+
14
+ protected
15
+
16
+ def excluded?(file)
17
+ return true if excludes.include?(file)
18
+ excludes.detect{ |exc| File.basename(exc).to_s.match(exc) }.nil?
19
+ end
20
+
21
+ def log_action(action, name)
22
+ name = name.gsub(dest_path, '').sub(/^\//, '')
23
+ Tipsy.logger.log_action(action, name)
24
+ end
25
+
26
+ ##
27
+ # By default make_file copies from one location to another
28
+ # Overridden in non-local scenarios
29
+ #
30
+ def make_file(source, destination)
31
+ log_action("create", destination)
32
+ FileUtils.cp(source, destination)
33
+ end
34
+
35
+ ##
36
+ # By default make_folder makes a matching folder in destination from source
37
+ # Overridden in non-local scenarios
38
+ #
39
+ def make_folder(dirname)
40
+ log_action("create", dirname)
41
+ FileUtils.mkdir(dirname)
42
+ end
43
+
44
+ ##
45
+ # Iterate through a file tree and process each file and folder.
46
+ #
47
+ def process_location(src, dest)
48
+ Dir.foreach(src) do |file|
49
+ next if excluded?(file)
50
+ source = File.join(src, file)
51
+ destination = File.join(dest, file)
52
+
53
+ if File.directory?(source)
54
+ make_folder(destination)
55
+ process_location(source, destination)
56
+ else
57
+ make_file(source, destination)
58
+ end
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,16 @@
1
+ module Tipsy
2
+ module Builder
3
+ class ExportBuilder < Base
4
+
5
+ def initialize
6
+ @source_path = Tipsy.root
7
+ @dest_path = Tipsy.options.build_path
8
+ end
9
+
10
+ def build!
11
+ FileUtils.mkdir(dest_path) unless File.exists?(dest_path) && File.directory?(dest_path)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,40 @@
1
+ require 'fileutils'
2
+ require 'erb'
3
+
4
+ module Tipsy
5
+ module Builder
6
+ class ProjectBuilder < Base
7
+ attr_reader :project
8
+
9
+ def initialize(name)
10
+ @project = name.camelize
11
+ @dest_path = File.join(Tipsy.root, name.underscore)
12
+ @source_path = File.expand_path("../../project", __FILE__)
13
+ end
14
+
15
+ def build!
16
+
17
+ FileUtils.mkdir(dest_path) unless File.exists?(dest_path)
18
+ super
19
+ cvars = Conf.new
20
+ cvars.root = dest_path
21
+ cvars.classname = @project
22
+ template = File.read(File.join(source_path, 'config.erb'))
23
+ config = ERB.new(template).result(cvars.get_binding)
24
+
25
+ File.open(File.join(dest_path, 'config.rb'), 'w'){ |io| io.write(config) }
26
+ log_action('create', File.join(dest_path, 'config.rb'))
27
+
28
+ Tipsy.logger.info("\n Project #{project} created in #{dest_path}.")
29
+ Tipsy.logger.info(" Run 'tipsy' from the root folder to start the server.\n\n")
30
+
31
+ end
32
+
33
+ class Conf
34
+ attr_accessor :classname, :root
35
+ def get_binding; binding; end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,14 @@
1
+ module Tipsy
2
+ module Builder
3
+
4
+ class RemoteBuilder < Base
5
+
6
+ def initialize
7
+ @source_path = Tipsy.root
8
+ @dest_path = ''
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'sass'
2
+
3
+ module Tipsy
4
+ module Compressors
5
+ class CssCompressor
6
+ def compress(css)
7
+ Sass::Engine.new(css, :syntax => :scss, :cache => false, :read_cache => false, :style => :compressed).render
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ ##
2
+ # Interface to Google's Online Closure Compiler.
3
+ # Uglifier is recommended (gem install uglifier) however to support environments where Node.js
4
+ # is unavailable this can be used as a fallback.
5
+ #
6
+ require 'net/http'
7
+ require 'uri'
8
+
9
+ module Tipsy
10
+ module Compressors
11
+ # http://closure-compiler.appspot.com/compile
12
+ class JavascriptCompressor
13
+ def compress(js)
14
+ return js if js.to_s.blank?
15
+ post_data = {
16
+ 'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
17
+ 'js_code' => js.to_s,
18
+ 'output_format' => 'text'
19
+ }
20
+ request = Net::HTTP.post_form(URI.parse('http://closure-compiler.appspot.com/compile'), post_data)
21
+ request.body.to_s
22
+ end
23
+ end
24
+ end
25
+ end
data/lib/tipsy/helpers.rb CHANGED
@@ -1,9 +1,32 @@
1
+ require 'active_support/core_ext/array'
2
+
3
+ require 'tipsy/helpers/asset_paths'
1
4
  require 'tipsy/helpers/capture'
2
5
  require 'tipsy/helpers/tag'
6
+ require 'tipsy/helpers/asset_tags'
7
+ require 'tipsy/helpers/sass'
3
8
 
4
9
  module Tipsy
5
10
  module Helpers
11
+ extend ActiveSupport::Concern
6
12
  include Capture
7
- include Tag
13
+ include Tag
14
+ include AssetPaths
15
+ include AssetTags
16
+
17
+ module InstanceMethods
18
+ private
19
+
20
+ def __initialize_helpers
21
+ module_names = []
22
+ includes = Dir.glob(File.expand_path(Tipsy.root) << "/helpers/*.rb").inject([]) do |arr, helper|
23
+ module_names << File.basename(helper, '.rb').classify
24
+ arr.concat File.open(helper).readlines
25
+ end
26
+ module_names.each{ |mod| includes.concat(["\n include #{mod}"]) }
27
+ self.class_eval(includes.join("\n"))
28
+ end
29
+ end
30
+
8
31
  end
9
32
  end
@@ -0,0 +1,19 @@
1
+ require 'pathname'
2
+
3
+ module Tipsy
4
+ module Helpers
5
+ module AssetPaths
6
+
7
+ def asset_path(path)
8
+ return path if path.match(/^https?:/) || Pathname.new(path).absolute?
9
+ "/" << File.join('assets', path)
10
+ end
11
+
12
+ def path_with_ext(path, ext)
13
+ return path if path.match(/^https?:/) || path.ends_with?(".#{ext}")
14
+ [path, ext].join('.')
15
+ end
16
+
17
+ end
18
+ end
19
+ end