tipsy 0.0.1 → 0.0.2

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.
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