summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/zorglub.rb5
-rw-r--r--lib/zorglub/app.rb213
-rw-r--r--lib/zorglub/engines/file.rb20
-rw-r--r--lib/zorglub/engines/haml.rb26
-rw-r--r--lib/zorglub/engines/sass.rb27
-rw-r--r--lib/zorglub/node.rb546
-rw-r--r--lib/zorglub/rack_session.rb10
-rw-r--r--lib/zorglub/session.rb288
-rw-r--r--spec/app_spec.rb58
-rw-r--r--spec/node_spec.rb602
-rw-r--r--spec/spec_helper.rb357
11 files changed, 1068 insertions, 1084 deletions
diff --git a/lib/zorglub.rb b/lib/zorglub.rb
index 586a184..b964bc5 100644
--- a/lib/zorglub.rb
+++ b/lib/zorglub.rb
@@ -1,11 +1,8 @@
#! /usr/bin/env ruby
-# -*- coding: UTF-8 -*-
module Zorglub
- VERSION = '0.1.0'
+ VERSION = '0.1.1'.freeze
end
require 'zorglub/node'
require 'zorglub/app'
-
-# EOF
diff --git a/lib/zorglub/app.rb b/lib/zorglub/app.rb
index 9619968..86adf1e 100644
--- a/lib/zorglub/app.rb
+++ b/lib/zorglub/app.rb
@@ -1,112 +1,113 @@
-# -*- coding: UTF-8 -*-
-
require 'rack'
module Zorglub
+ class App < Rack::URLMap
+ def initialize(map = {}, &block)
+ super
+ @map = map
+ @engines_cache = {}
+ @options = {
+ debug: false,
+ root: '.',
+ layout: 'default',
+ view_dir: 'view',
+ layout_dir: 'layout',
+ static_dir: 'static',
+ engine: nil,
+ engines_cache_enabled: true,
+ engines: {},
+ haml_options: {
+ format: :html5,
+ encoding: 'utf-8'
+ },
+ sass_options: {
+ syntax: :scss,
+ cache: false,
+ style: :compressed
+ },
+ session_options: {
+ enabled: false,
+ key: 'zorglub.sid',
+ secret: 'session-secret-secret',
+ sid_len: 64
+ }
+ }
+ instance_eval(&block) if block_given?
+ remap @map
+ end
+
+ attr_reader :engines_cache
+
+ def map(location, object)
+ return unless location && object
+ raise StandardError, "#{@map[location]} already mapped to #{location}" if @map.key? location
+
+ object.app = self
+ @map.merge! location.to_s => object
+ remap @map
+ end
+
+ def delete(location)
+ @map.delete location
+ remap @map
+ end
+
+ def at(location)
+ @map[location]
+ end
+
+ def to(object)
+ @map.invert[object]
+ end
+
+ def to_hash
+ @map.dup
+ end
+
+ # OPTIONS @options
+
+ def opt(sym)
+ @options[sym]
+ end
+
+ def opt!(sym, val)
+ @options[sym] = val
+ end
+
+ def register_engine!(name, ext, proc)
+ x = if ext.nil? || ext.empty?
+ nil
+ elsif ext[0] == '.'
+ ext.length == 1 ? nil : ext
+ else
+ ".#{ext}"
+ end
+ @options[:engines][name] = [proc, x]
+ end
+
+ def engine_proc_ext(engine, ext)
+ p, x = @options[:engines][engine]
+ return [nil, ''] if p.nil?
+
+ [p, ext.nil? || ext.empty? ? x : ext]
+ end
+
+ def view_base_path
+ _base_path @options[:view_path], :view_dir
+ end
+
+ def layout_base_path
+ _base_path @options[:layout_path], :layout_dir
+ end
+
+ def static_base_path
+ _base_path @options[:static_path], :static_dir
+ end
+
+ private
- class App < Rack::URLMap
-
- def initialize map={}, &block
- super
- @map = map
- @engines_cache = { }
- @options = {
- :debug => false,
- :root => '.',
- :layout => 'default',
- :view_dir => 'view',
- :layout_dir => 'layout',
- :static_dir => 'static',
- :engine => nil,
- :engines_cache_enabled => true,
- :engines => { },
- :haml_options => {
- :format => :html5,
- :encoding => 'utf-8'
- },
- :sass_options => {
- :syntax => :scss,
- :cache => :false,
- :style => :compressed
- },
- :session_options => {
- :enabled => false,
- :key => 'zorglub.sid',
- :secret => 'session-secret-secret',
- :sid_len => 64
- }
- }
- instance_eval &block if block_given?
- remap @map
- end
-
- attr_reader :engines_cache
-
- def map location, object
- return unless location and object
- raise Exception.new "#{@map[location]} already mapped to #{location}" if @map.has_key? location
- object.app = self
- @map.merge! location.to_s=>object
- remap @map
- end
-
- def delete location
- @map.delete location
- remap @map
- end
-
- def at location
- @map[location]
- end
-
- def to object
- @map.invert[object]
- end
-
- def to_hash
- @map.dup
- end
-
- # OPTIONS @options
-
- def opt sym
- @options[sym]
- end
-
- def opt! sym, val
- @options[sym] = val
- end
-
- def register_engine! name, ext, proc
- if ext.nil? or ext.empty?
- x = nil
- else
- x = (ext[0]=='.' ? (ext.length==1 ? nil : ext) : '.' + ext)
- end
- @options[:engines][name]=[ proc, x ]
- end
-
- def engine_proc_ext engine, ext
- p,x = @options[:engines][engine]
- return [nil, ''] if p.nil?
- [ p, ((ext.nil? or ext.empty?) ? x : ext ) ]
- end
-
- def view_base_path
- _base_path @options[:view_path], :view_dir
- end
-
- def layout_base_path
- _base_path @options[:layout_path], :layout_dir
- end
-
- def static_base_path
- _base_path @options[:static_path], :static_dir
- end
-
- private
- def _base_path p, sym
- ( p.nil? ? File.join(@options[:root], @options[sym]) : p )
- end
+ def _base_path(path, sym)
+ path.nil? ? File.join(@options[:root], @options[sym]) : path
end
+ end
end
diff --git a/lib/zorglub/engines/file.rb b/lib/zorglub/engines/file.rb
index dbf579d..748f701 100644
--- a/lib/zorglub/engines/file.rb
+++ b/lib/zorglub/engines/file.rb
@@ -1,18 +1,14 @@
-# -*- coding: UTF-8 -*-
-
require 'haml/util'
require 'haml/engine'
module Zorglub
- module Engines
- module File
- def self.proc path,obj
- content = ::File.open(path,'r'){|f| f.read }
- ext = path.sub /.*\.(.+)$/,'\1'
- return content, "text/#{ext}"
- end
- end
+ module Engines
+ module File
+ def self.proc(path, _obj)
+ content = ::File.read(path)
+ ext = path.sub(/.*\.(.+)$/, '\1')
+ [content, "text/#{ext}"]
+ end
end
+ end
end
-
-# EOF
diff --git a/lib/zorglub/engines/haml.rb b/lib/zorglub/engines/haml.rb
index e5013f8..b602773 100644
--- a/lib/zorglub/engines/haml.rb
+++ b/lib/zorglub/engines/haml.rb
@@ -1,22 +1,18 @@
-# -*- coding: UTF-8 -*-
-
require 'haml/util'
require 'haml/template'
module Zorglub
- module Engines
- module Haml
- def self.proc path,obj
- haml = ::Haml::Template.new( path )
- if obj.app.opt(:engines_cache_enabled)
- key = path.sub obj.app.opt(:root),''
- obj.app.engines_cache[key] ||= haml
- end
- html = haml.render(obj, obj.app.opt(:haml_options))
- return html, 'text/html'
- end
+ module Engines
+ module Haml
+ def self.proc(path, obj)
+ haml = ::Haml::Template.new(path)
+ if obj.app.opt(:engines_cache_enabled)
+ key = path.sub obj.app.opt(:root), ''
+ obj.app.engines_cache[key] ||= haml
end
+ html = haml.render(obj, obj.app.opt(:haml_options))
+ [html, 'text/html']
+ end
end
+ end
end
-
-# EOF
diff --git a/lib/zorglub/engines/sass.rb b/lib/zorglub/engines/sass.rb
index bc6b759..44973d5 100644
--- a/lib/zorglub/engines/sass.rb
+++ b/lib/zorglub/engines/sass.rb
@@ -1,22 +1,17 @@
-# -*- coding: UTF-8 -*-
-
require 'sass'
module Zorglub
- module Engines
- module Sass
- def self.proc path,obj
- if obj.app.opt(:engines_cache_enabled)
- key = path.sub obj.app.opt(:root),''
- sass = obj.app.engines_cache[key] ||= ::Sass::Engine.new( ::File.open(path,'r'){|f| f.read }, obj.app.opt(:sass_options) )
- else
- sass = ::Sass::Engine.new( ::File.open(path,'r'){|f| f.read }, obj.app.opt(:sass_options) )
- end
- css = sass.render
- return css, 'text/css'
- end
+ module Engines
+ module Sass
+ def self.proc(path, obj)
+ sass = ::Sass::Engine.new(::File.read(path), obj.app.opt(:sass_options))
+ if obj.app.opt(:engines_cache_enabled)
+ key = path.sub obj.app.opt(:root), ''
+ obj.app.engines_cache[key] ||= sass
end
+ css = sass.render
+ [css, 'text/css']
+ end
end
+ end
end
-
-# EOF
diff --git a/lib/zorglub/node.rb b/lib/zorglub/node.rb
index b360a5c..84cba92 100644
--- a/lib/zorglub/node.rb
+++ b/lib/zorglub/node.rb
@@ -1,334 +1,334 @@
-# -*- coding: UTF-8 -*-
-
require 'fileutils'
module Zorglub
+ class Node
+ UNDEFINED = -1
- class Node
-
- UNDEFINED=-1
-
- # class level engine, layout, static, layout_base_path, view_base_path configuration
+ # class level engine, layout, static, layout_base_path, view_base_path configuration
- class << self
+ class << self
+ attr_reader :static, :cache_lifetime
- attr_reader :static, :cache_lifetime
+ def engine!(engine)
+ @engine = engine
+ end
- def engine! engine
- @engine = engine
- end
+ def engine
+ @engine = @app.opt(:engine) if @engine == UNDEFINED && @app
+ @engine
+ end
- def engine
- @engine = @app.opt(:engine) if @engine==UNDEFINED and @app
- @engine
- end
+ def no_layout!
+ layout! nil
+ end
- def no_layout!
- layout! nil
- end
+ def layout!(layout)
+ @layout = layout
+ end
- def layout! layout
- @layout = layout
- end
+ def layout
+ @layout = @app.opt(:layout) if @layout == UNDEFINED && @app
+ @layout
+ end
- def layout
- @layout = @app.opt(:layout) if @layout==UNDEFINED and @app
- @layout
- end
+ def static!(val, lifetime = 0)
+ @static = [true, false].include?(val) ? val : false
+ @cache_lifetime = lifetime
+ end
- def static! val, lifetime=0
- @static = ( (val==true or val==false) ? val : false )
- @cache_lifetime = lifetime
- end
+ def layout_base_path!(path)
+ @layout_base_path = path
+ end
- def layout_base_path! path
- @layout_base_path = path
- end
+ def layout_base_path
+ @layout_base_path ||= @app.layout_base_path
+ end
- def layout_base_path
- @layout_base_path ||= @app.layout_base_path
- end
+ def view_base_path!(path)
+ @view_base_path = path
+ end
- def view_base_path! path
- @view_base_path = path
- end
-
- def view_base_path
- @view_base_path ||= @app.view_base_path
- end
- end
-
- # instance level engine, layout, view, static configuration
+ def view_base_path
+ @view_base_path ||= @app.view_base_path
+ end
+ end
- def engine! engine
- @engine = engine
- end
+ # instance level engine, layout, view, static configuration
- def no_layout!
- layout! nil
- end
+ def engine!(engine)
+ @engine = engine
+ end
- def layout! layout
- @layout = layout
- end
+ def no_layout!
+ layout! nil
+ end
- def layout
- return nil if @layout.nil?
- File.join(self.class.layout_base_path, @layout) + ext
- end
+ def layout!(layout)
+ @layout = layout
+ end
- def no_view!
- view! nil
- end
+ def layout
+ return nil if @layout.nil?
- def view! view
- @view = view
- end
+ File.join(self.class.layout_base_path, @layout) + ext
+ end
- def view
- return nil if @view.nil?
- File.join(self.class.view_base_path, @view) + ext
- end
+ def no_view!
+ view! nil
+ end
- def static! val, lifetime=0
- @static = ( (val==true or val==false) ? val : false )
- @cache_lifetime = lifetime
- end
+ def view!(view)
+ @view = view
+ end
- def static
- return nil if not @static or @view.nil?
- File.join(app.static_base_path, @view) + ext
- end
+ def view
+ return nil if @view.nil?
- def ext! ext
- @ext = ( (ext.nil? or ext.empty?) ? nil : (ext[0]=='.' ? (ext.length==1 ? nil : ext) : '.' + ext) )
- end
+ File.join(self.class.view_base_path, @view) + ext
+ end
- def ext
- @ext || ''
- end
+ def static!(val, lifetime = 0)
+ @static = [true, false].include?(val) ? val : false
+ @cache_lifetime = lifetime
+ end
- def mime! mime
- @mime = mime
- end
+ def static
+ return nil if !@static || @view.nil?
- # class level basic node functions
+ File.join(app.static_base_path, @view) + ext
+ end
- class << self
+ def ext!(ext)
+ @ext = if ext.nil? || ext.empty?
+ nil
+ elsif ext[0] == '.'
+ ext.length == 1 ? nil : ext
+ else
+ ".#{ext}"
+ end
+ end
- attr_accessor :app
- def map app, location
- @app = app
- @app.map location, self
- end
+ def ext
+ @ext || ''
+ end
- def r *args
- @r ||= @app.to self
- (args.empty? ? @r : File.join( @r, args.map { |x| x.to_s } ) )
- end
+ def mime!(mime)
+ @mime = mime
+ end
- end
+ # class level basic node functions
- # instance level basic node functions
+ class << self
+ attr_accessor :app
- def app
- self.class.app
- end
+ def map(app, location)
+ @app = app
+ @app.map location, self
+ end
- def map
- self.class.r
- end
+ def r *args
+ @r ||= @app.to self
+ args.empty? ? @r : File.join(@r, args.map(&:to_s))
+ end
+ end
- def r *args
- File.join map, (args.empty? ? meth : args.map { |x| x.to_s } )
- end
+ # instance level basic node functions
- def html
- [ :map, :r, :args, :engine, :layout, :view ].inject('') { |s,sym| s+="<p>#{sym} => #{self.send sym}</p>"; s }
- end
+ def app
+ self.class.app
+ end
- def redirect target, options={}, &block
- status = options[:status] || 302
- body = options[:body] || redirect_body(target)
- header = response.headers.merge('Location' => target.to_s)
- throw :stop_realize, Rack::Response.new(body, status, header, &block)
- end
+ def map
+ self.class.r
+ end
- def redirect_body target
- "You are being redirected, please follow this link to: <a href='#{target}'>#{target}</a>!"
- end
+ def r *args
+ File.join map, (args.empty? ? meth : args.map(&:to_s))
+ end
- # class level inherited values are key=>array, copied at inheritance
- # so they can be extanded at class level
- # values are copied from class into instance at object creation
- # so that can be extanded without modifying class level values
- # typical usage are css or js inclusions
+ def html
+ %i[map r args engine layout view].inject('') { |s, sym| s + "<p>#{sym} => #{send sym}</p>" }
+ end
- @cli_vals = { }
+ def redirect(target, options = {}, &block)
+ status = options[:status] || 302
+ body = options[:body] || redirect_body(target)
+ header = response.headers.merge('Location' => target.to_s)
+ throw :stop_realize, Rack::Response.new(body, status, header, &block)
+ end
- class << self
+ def redirect_body(target)
+ "You are being redirected, please follow this link to: <a href='#{target}'>#{target}</a>!"
+ end
- attr_reader :cli_vals
+ # class level inherited values are key=>array, copied at inheritance
+ # so they can be extanded at class level
+ # values are copied from class into instance at object creation
+ # so that can be extanded without modifying class level values
+ # typical usage are css or js inclusions
- def cli_val sym, *args
- vals = @cli_vals[sym] ||= []
- unless args.empty?
- vals.concat args
- vals.uniq!
- end
- vals
- end
+ @cli_vals = {}
- end
+ class << self
+ attr_reader :cli_vals
- def cli_val sym, *args
- vals = @cli_vals[sym] ||= []
- unless args.empty?
- vals.concat args
- vals.uniq!
- end
- vals
+ def cli_val(sym, *args)
+ vals = @cli_vals[sym] ||= []
+ unless args.empty?
+ vals.concat args
+ vals.uniq!
end
+ vals
+ end
+ end
- # before_all and after_all hooks
-
- @cli_vals[:before_all] = []
- @cli_vals[:after_all] = []
- class << self
-
- def call_before_hooks obj
- @cli_vals[:before_all].each do |blk| blk.call obj end
- end
-
- def before_all meth=nil, &blk
- @cli_vals[:before_all]<< ( meth.nil? ? blk : meth )
- @cli_vals[:before_all].uniq!
- end
-
- def call_after_hooks obj
- @cli_vals[:after_all].each do |blk| blk.call obj end
- end
+ def cli_val(sym, *args)
+ vals = @cli_vals[sym] ||= []
+ unless args.empty?
+ vals.concat args
+ vals.uniq!
+ end
+ vals
+ end
- def after_all meth=nil, &blk
- @cli_vals[:after_all]<< ( meth.nil? ? blk : meth )
- @cli_vals[:after_all].uniq!
- end
+ # before_all and after_all hooks
- end
+ @cli_vals[:before_all] = []
+ @cli_vals[:after_all] = []
+ class << self
+ def call_before_hooks(obj)
+ @cli_vals[:before_all].each { |blk| blk.call obj }
+ end
- # rack entry point, page computation methods
-
- class << self
-
- def inherited sub
- sub.engine! ( engine || (self==Zorglub::Node ? UNDEFINED : nil ) )
- sub.layout! ( layout || (self==Zorglub::Node ? UNDEFINED : nil ) )
- sub.instance_variable_set :@cli_vals, {}
- @cli_vals.each do |s,v| sub.cli_val s, *v end
- end
-
- def call env
- meth, *args = env['PATH_INFO'].sub(/^\/+/,'').split(/\//)
- meth ||= 'index'
- $stderr << "=> #{meth}(#{args.join ','})\n" if app.opt :debug
- node = self.new env, meth, args
- return error_404 node, meth if not node.respond_to? meth
- node.realize!
- end
-
- def partial env, meth, *args
- node = self.new env, meth.to_s, args, true
- return error_404 node, meth if not node.respond_to? meth
- node.feed! env[:no_hooks]
- node.content
- end
-
- def error_404 node, meth
- $stderr << " !! #{node.class.name}::#{meth} not found\n" if app.opt :debug
- resp = node.response
- resp.status = 404
- resp['Content-Type'] = 'text/plain'
- resp.write "%s mapped at %p can't respond to : %p" % [ node.class.name, node.map, node.meth ]
- resp
- end
+ def before_all(meth = nil, &blk)
+ @cli_vals[:before_all] << (meth.nil? ? blk : meth)
+ @cli_vals[:before_all].uniq!
+ end
- end
+ def call_after_hooks(obj)
+ @cli_vals[:after_all].each { |blk| blk.call obj }
+ end
- attr_reader :request, :response, :content, :mime, :state, :engine, :meth, :args
-
- def initialize env, meth, args, partial=false
- @meth = meth
- @args = args
- @partial = partial
- @request = Rack::Request.new env
- @response = Rack::Response.new
- @cli_vals ={}
- @debug = app.opt :debug
- @engine = self.class.engine
- @layout = ( partial ? nil : self.class.layout )
- @view = r(meth)
- @static = self.class.static
- @cache_lifetime = self.class.cache_lifetime
- self.class.cli_vals.each do |s,v| cli_val s, *v end
- end
+ def after_all(meth = nil, &blk)
+ @cli_vals[:after_all] << (meth.nil? ? blk : meth)
+ @cli_vals[:after_all].uniq!
+ end
+ end
- def realize!
- catch(:stop_realize) {
- feed!
- response.write @content
- response.headers['Content-Type'] ||= ( @mime || 'text/html' )
- response.finish
- response
- }
- end
+ # rack entry point, page computation methods
+
+ class << self
+ def inherited(sub)
+ super
+ sub.engine!(engine || (self == Zorglub::Node ? UNDEFINED : nil))
+ sub.layout!(layout || (self == Zorglub::Node ? UNDEFINED : nil))
+ sub.instance_variable_set :@cli_vals, {}
+ @cli_vals.each { |s, v| sub.cli_val s, *v }
+ end
+
+ def call(env)
+ meth, *args = env['PATH_INFO'].sub(%r{^/+}, '').split(%r{/})
+ meth ||= 'index'
+ $stderr << "=> #{meth}(#{args.join ','})\n" if app.opt :debug
+ node = new(env, meth, args)
+ return error404 node, meth unless node.respond_to? meth
+
+ node.realize!
+ end
+
+ def partial(env, meth, *args)
+ node = new env, meth.to_s, args, true
+ return error404 node, meth unless node.respond_to? meth
+
+ node.feed! env[:no_hooks]
+ node.content
+ end
+
+ def error404(node, meth)
+ $stderr << " !! #{node.class.name}::#{meth} not found\n" if app.opt :debug
+ resp = node.response
+ resp.status = 404
+ resp['Content-Type'] = 'text/plain'
+ resp.write "%<node.class.name>s mapped at %<node.map>p can't respond to : %<node.meth>p"
+ resp
+ end
+ end
- def feed! no_hooks=false
- @state = :pre_cb
- self.class.call_before_hooks self unless no_hooks
- @state = :meth
- @content = self.send @meth, *@args
- static_path = static
- if static_path.nil?
- compile_page!
- else
- static_page! static_path
- end
- @state = :post_cb
- self.class.call_after_hooks self unless no_hooks
- @state = :finished
- return @content, @mime
- end
+ attr_reader :request, :response, :content, :mime, :state, :engine, :meth, :args
+
+ def initialize(env, meth, args, partial = false)
+ @meth = meth
+ @args = args
+ @partial = partial
+ @request = Rack::Request.new env
+ @response = Rack::Response.new
+ @cli_vals = {}
+ @debug = app.opt :debug
+ @engine = self.class.engine
+ @layout = (partial ? nil : self.class.layout)
+ @view = r(meth)
+ @static = self.class.static
+ @cache_lifetime = self.class.cache_lifetime
+ self.class.cli_vals.each { |s, v| cli_val s, *v }
+ end
- def static_page! path
- if File.exist?(path) and ( @cache_lifetime.nil? or @cache_lifetime==0 or ( (Time.now-File.stat(path).mtime) < @cache_lifetime ) )
- $stderr << " * use cache file : #{path}\n" if @debug
- content = File.open(path, 'r') {|f| f.read }
- @content = content.sub /^@mime:(.*)\n/,''
- @mime = $1
- else
- compile_page!
- FileUtils.mkdir_p File.dirname(path)
- File.open(path, 'w') {|f| f.write("@mime:"+@mime+"\n"); f.write(@content); }
- $stderr << " * cache file created : #{path}\n" if @debug
- end
- end
+ def realize!
+ catch(:stop_realize) do
+ feed!
+ response.write @content
+ response.headers['Content-Type'] ||= @mime || 'text/html'
+ response.finish
+ response
+ end
+ end
- def compile_page!
- e, @ext = app.engine_proc_ext @engine, @ext
- v, l = view, layout
- if @debug
- $stderr << " * "+(e ? 'use engine' : 'no engine ')+" : "+(e ? e.to_s : '')+"\n"
- $stderr << " * "+((l and File.exist?(l)) ? 'use layout' : 'no layout ')+" : "+(l ? l : '')+"\n"
- $stderr << " * "+((v and File.exist?(v)) ? 'use view ' : 'no view ')+" : "+(v ? v : '')+"\n"
- end
- @state = ( @partial ? :partial : :view )
- @content, mime = e.call v, self if e and v and File.exist? v
- @mime ||= mime
- @state = :layout
- @content, mime = e.call l, self if e and l and File.exist? l
- @mime = mime if @mime.nil? and not mime.nil?
- end
+ def feed!(no_hooks = false)
+ @state = :pre_cb
+ self.class.call_before_hooks self unless no_hooks
+ @state = :meth
+ @content = send @meth, *@args
+ static_path = static
+ if static_path.nil?
+ compile_page!
+ else
+ static_page! static_path
+ end
+ @state = :post_cb
+ self.class.call_after_hooks self unless no_hooks
+ @state = :finished
+ [@content, @mime]
+ end
+ def static_page!(path)
+ if File.exist?(path) && (@cache_lifetime.nil? || @cache_lifetime.zero? ||
+ (Time.now - File.stat(path).mtime) < @cache_lifetime)
+ $stderr << " * use cache file : #{path}\n" if @debug
+ content = File.read(path)
+ @content = content.sub(/^@mime:(.*)\n/, '')
+ @mime = ::Regexp.last_match(1)
+ else
+ compile_page!
+ FileUtils.mkdir_p File.dirname(path)
+ File.open(path, 'w') { |f| f.write("@mime:#{@mime}\n#{@content}") }
+ $stderr << " * cache file created : #{path}\n" if @debug
+ end
end
+ def compile_page!
+ e, @ext = app.engine_proc_ext @engine, @ext
+ v = view
+ l = layout
+ if @debug
+ $stderr << " * #{e ? 'use engine' : 'no engine '} : #{e ? e.to_s : ''}\n"
+ $stderr << " * #{l && File.exist?(l) ? 'use layout' : 'no layout '} : #{l || ''}\n"
+ $stderr << " * #{v && File.exist?(v) ? 'use view ' : 'no view '} : #{v || ''}\n"
+ end
+ @state = @partial ? :partial : :view
+ @content, mime = e.call(v, self) if e && v && File.exist?(v)
+ @mime ||= mime
+ @state = :layout
+ @content, mime = e.call(l, self) if e && l && File.exist?(l)
+ @mime = mime if @mime.nil? && !mime.nil?
+ end
+ end
end
diff --git a/lib/zorglub/rack_session.rb b/lib/zorglub/rack_session.rb
index d08cd84..c78bb37 100644
--- a/lib/zorglub/rack_session.rb
+++ b/lib/zorglub/rack_session.rb
@@ -1,9 +1,7 @@
-# -*- coding: UTF-8 -*-
-
module Zorglub
- class Node
- def session
- @request.session
- end
+ class Node
+ def session
+ @request.session
end
+ end
end
diff --git a/lib/zorglub/session.rb b/lib/zorglub/session.rb
index fc5fdbe..05b91d6 100644
--- a/lib/zorglub/session.rb
+++ b/lib/zorglub/session.rb
@@ -1,152 +1,148 @@
-# -*- coding: UTF-8 -*-
-
require 'securerandom'
module Zorglub
+ class Node
+ @sessions = {}
+
+ class << self
+ attr_reader :sessions
+ end
+
+ def session
+ @session ||= SessionHash.new @request, @response, Node.sessions, app.opt(:session_options)
+ end
+ end
+
+ class SessionHash < Hash
+ def initialize(req, resp, sessions, options)
+ @request = req
+ @response = resp
+ @sessions = sessions
+ @sid = nil
+ @options = options
+ super()
+ end
+
+ def [](key)
+ load_data!
+ super key
+ end
+
+ def key?(key)
+ load_data!
+ super key
+ end
+ alias include? key?
+
+ def []=(key, value)
+ load_data!
+ super key, value
+ end
+
+ def clear
+ load_data!
+ # @response.delete_cookie @options[:key]
+ # @sessions.delete @sid
+ # @sid = nil
+ super
+ end
+
+ def to_hash
+ load_data!
+ h = {}.replace(self)
+ h.delete_if { |_k, v| v.nil? }
+ h
+ end
+
+ def update(hash)
+ load_data!
+ super stringify_keys(hash)
+ end
+
+ def delete(key)
+ load_data!
+ super key
+ end
+
+ def inspect
+ if loaded?
+ super
+ else
+ "#<#{self.class}:0x#{object_id.to_s(16)} not yet loaded>"
+ end
+ end
+
+ def exists?
+ loaded? ? @sessions.key?(@sid) : false
+ end
+
+ def loaded?
+ !@sid.nil?
+ end
+
+ def empty?
+ load_data!
+ super
+ end
+
+ private
+
+ def load_data!
+ return if loaded?
+ return unless @options[:enabled]
+
+ sid = @request.cookies[@options[:key]]
+ if sid.nil?
+ sid = generate_sid!
+ @response.set_cookie @options[:key], sid
+ end
+ replace @sessions[sid] ||= {}
+ @sessions[sid] = self
+ @sid = sid
+ end
+
+ def stringify_keys(other)
+ hash = {}
+ other.each do |key, value|
+ hash[key] = value
+ end
+ hash
+ end
+
+ def generate_sid!
+ begin sid = sid_algorithm end while @sessions.key? sid
+ sid
+ end
- class Node
-
- @sessions = {}
-
- class << self
- attr_reader :sessions
- end
-
- def session
- @session ||= SessionHash.new @request, @response, Node.sessions, app.opt(:session_options)
- end
- end
-
- class SessionHash < Hash
-
- def initialize req, resp, sessions, options
- @request = req
- @response = resp
- @sessions = sessions
- @sid = nil
- @options = options
- super()
- end
-
- def [] key
- load_data!
- super key
- end
-
- def has_key? key
- load_data!
- super key
- end
- alias :key? :has_key?
- alias :include? :has_key?
-
- def []= key, value
- load_data!
- super key, value
- end
-
- def clear
- load_data!
- # @response.delete_cookie @options[:key]
- # @sessions.delete @sid
- # @sid = nil
- super
- end
-
- def to_hash
- load_data!
- h = {}.replace(self)
- h.delete_if { |k,v| v.nil? }
- h
- end
-
- def update hash
- load_data!
- super stringify_keys(hash)
- end
-
- def delete key
- load_data!
- super key
- end
-
- def inspect
- if loaded?
- super
- else
- "#<#{self.class}:0x#{self.object_id.to_s(16)} not yet loaded>"
- end
- end
-
- def exists?
- ( loaded? ? @sessions.has_key?(@sid) : false )
- end
-
- def loaded?
- not @sid.nil?
- end
-
- def empty?
- load_data!
- super
- end
-
- private
-
- def load_data!
- return if loaded?
- if @options[:enabled]
- sid = @request.cookies[@options[:key]]
- if sid.nil?
- sid = generate_sid!
- @response.set_cookie @options[:key], sid
- end
- replace @sessions[sid] ||={}
- @sessions[sid] = self
- @sid = sid
- end
- end
-
- def stringify_keys other
- hash = {}
- other.each do |key, value|
- hash[key] = value
- end
- hash
- end
-
- def generate_sid!
- begin sid = sid_algorithm end while @sessions.has_key? sid
- sid
- end
-
- begin
- require 'securerandom'
- # Using SecureRandom, optional length.
- # SecureRandom is available since Ruby 1.8.7.
- # For Ruby versions earlier than that, you can require the uuidtools gem,
- # which has a drop-in replacement for SecureRandom.
- def sid_algorithm; SecureRandom.hex(@options[:sid_len]); end
- rescue LoadError
- require 'openssl'
- # Using OpenSSL::Random for generation, this is comparable in performance
- # with stdlib SecureRandom and also allows for optional length, it should
- # have the same behaviour as the SecureRandom::hex method of the
- # uuidtools gem.
- def sid_algorithm
- OpenSSL::Random.random_bytes(@options[:sid_len] / 2).unpack('H*')[0]
- end
- rescue LoadError
- # Digest::SHA2::hexdigest produces a string of length 64, although
- # collisions are not very likely, the entropy is still very low and
- # length is not optional.
- #
- # Replacing it with OS-provided random data would take a lot of code and
- # won't be as cross-platform as Ruby.
- def sid_algorithm
- entropy = [ srand, rand, Time.now.to_f, rand, $$, rand, object_id ]
- Digest::SHA2.hexdigest(entropy.join)
- end
- end
+ begin
+ require 'securerandom'
+ # Using SecureRandom, optional length.
+ # SecureRandom is available since Ruby 1.8.7.
+ # For Ruby versions earlier than that, you can require the uuidtools gem,
+ # which has a drop-in replacement for SecureRandom.
+ def sid_algorithm
+ SecureRandom.hex(@options[:sid_len])
+ end
+ rescue LoadError
+ require 'openssl'
+ # Using OpenSSL::Random for generation, this is comparable in performance
+ # with stdlib SecureRandom and also allows for optional length, it should
+ # have the same behaviour as the SecureRandom::hex method of the
+ # uuidtools gem.
+ def sid_algorithm
+ OpenSSL::Random.random_bytes(@options[:sid_len] / 2).unpack1('H*')[0]
+ end
+ rescue LoadError
+ # Digest::SHA2::hexdigest produces a string of length 64, although
+ # collisions are not very likely, the entropy is still very low and
+ # length is not optional.
+ #
+ # Replacing it with OS-provided random data would take a lot of code and
+ # won't be as cross-platform as Ruby.
+ def sid_algorithm
+ entropy = [srand, rand, Time.now.to_f, rand, $$, rand, object_id]
+ Digest::SHA2.hexdigest(entropy.join)
+ end
end
+ end
end
diff --git a/spec/app_spec.rb b/spec/app_spec.rb
index 2d7aaeb..9864939 100644
--- a/spec/app_spec.rb
+++ b/spec/app_spec.rb
@@ -1,43 +1,37 @@
-# -*- coding: UTF-8 -*-
-
require 'spec_helper'
describe Zorglub do
+ describe Zorglub::App do
+ it 'map should add a mapped node' do
+ expect(APP.at('/temp')).to be_nil
+ APP.map '/temp', Temp
+ expect(APP.at('/temp')).to be Temp
+ end
- describe Zorglub::App do
-
- it "map should add a mapped node" do
- expect(APP.at("/temp")).to be_nil
- APP.map "/temp", Temp
- expect(APP.at("/temp")).to be Temp
- end
-
- it "delete should delete a mapped node" do
- expect(APP.at("/temp")).to be Temp
- APP.delete "/temp"
- expect(APP.at("/temp")).to be_nil
- end
-
- it "at should return mapped node" do
- expect(APP.at("/node1")).to be Node1
- end
-
- it "at should return nil if no Node mapped" do
- expect(APP.at("/none")).to be_nil
- end
+ it 'delete should delete a mapped node' do
+ expect(APP.at('/temp')).to be Temp
+ APP.delete '/temp'
+ expect(APP.at('/temp')).to be_nil
+ end
- it "to should return path to node" do
- expect(APP.to(Node1)).to eq "/node1"
- end
+ it 'at should return mapped node' do
+ expect(APP.at('/node1')).to be Node1
+ end
- it "to should return nil if not an existing Node" do
- expect(APP.to(nil)).to be_nil
- end
+ it 'at should return nil if no Node mapped' do
+ expect(APP.at('/none')).to be_nil
+ end
- it "to_hash should return a correct hash" do
- expect(APP.to_hash["/node1"]).to be Node1
- end
+ it 'to should return path to node' do
+ expect(APP.to(Node1)).to eq '/node1'
+ end
+ it 'to should return nil if not an existing Node' do
+ expect(APP.to(nil)).to be_nil
end
+ it 'to_hash should return a correct hash' do
+ expect(APP.to_hash['/node1']).to be Node1
+ end
+ end
end
diff --git a/spec/node_spec.rb b/spec/node_spec.rb
index f77d7c3..fe1edfb 100644
--- a/spec/node_spec.rb
+++ b/spec/node_spec.rb
@@ -1,315 +1,309 @@
-# -*- coding: UTF-8 -*-
-
require 'spec_helper'
def clean_static_path
- static_base_path = Node0.app.static_base_path
- Dir.glob( File.join(static_base_path,'**','*') ).each do |f| File.unlink f if File.file? f end
- Dir.glob( File.join(static_base_path,'*') ).each do |d| Dir.rmdir d end
- Dir.rmdir static_base_path if File.directory? static_base_path
+ static_base_path = Node0.app.static_base_path
+ Dir.glob(File.join(static_base_path, '**', '*')).each { |f| File.unlink f if File.file? f }
+ Dir.glob(File.join(static_base_path, '*')).each { |d| Dir.rmdir d }
+ Dir.rmdir static_base_path if File.directory? static_base_path
end
describe Zorglub do
+ describe Zorglub::Node do
+ before(:all) do
+ clean_static_path
+ end
+
+ after(:all) do
+ clean_static_path
+ end
+
+ it "engine should return default Node's engine" do
+ expect(Node0.engine).to eq Node0.app.opt(:engine)
+ end
+
+ it "layout should return default Node's layout" do
+ expect(Node0.layout).to eq Node0.app.opt(:layout)
+ end
+
+ it "engine should return class defined Node's engine" do
+ expect(Node1.engine).to eq 'engine-1'
+ expect(Node3.engine).to eq 'engine-2'
+ end
+
+ it "layout should return class defined Node's layout" do
+ expect(Node1.layout).to eq 'layout-1'
+ expect(Node3.layout).to eq 'layout-2'
+ end
+
+ it 'engine should return engine inherited from Node2' do
+ expect(Node2.engine).to eq 'engine-1'
+ end
+
+ it 'layout should return layout inherited from Node2' do
+ expect(Node2.layout).to eq 'layout-1'
+ end
+
+ it 'r should build a well formed path' do
+ expect(Node1.r(1, 'arg2', 'some')).to eq '/node1/1/arg2/some'
+ end
+
+ it 'instance level map should work' do
+ r = Node0.my_call '/with_2args/1/2'
+ h = YAML.load r.body[0]
+ expect(h[:map]).to eq '/node0'
+ end
+
+ it 'should return err404 response when no method found' do
+ expect(Node0.respond_to?('noresponse')).to be_falsey
+ r = Node0.my_call '/noresponse'
+ expect(r.status).to eq 404
+ end
+
+ it 'simple method should respond' do
+ r = Node0.my_call '/hello'
+ expect(r.status).to eq 200
+ expect(r.body[0]).to eq 'world'
+ end
+
+ it 'instance level args should work' do
+ r = Node0.my_call '/with_2args/1/2'
+ h = YAML.load r.body[0]
+ expect(h[:args][0]).to eq '1'
+ expect(h[:args][1]).to eq '2'
+ end
+
+ it 'should raise error when too much arguments' do
+ expect(-> { Node0.my_call '/with_2args/1/2/3' }).to raise_error ArgumentError
+ end
+
+ it 'layout proc, method level layout and engine definitions should work' do
+ r = Node0.my_call '/index'
+ expect(r.status).to eq 200
+ h = YAML.load r.body[0]
+ ly = File.join Node0.app.layout_base_path, Node0.layout
+ vu = File.join Node0.app.view_base_path, Node0.r, 'index'
+ expect(h[:path]).to eq ly
+ expect(h[:layout]).to eq ly
+ expect(h[:view]).to eq vu
+ end
+
+ it 'layout proc, method level layout and engine definitions should work' do
+ r = Node1.my_call '/index'
+ expect(r.status).to eq 200
+ h = YAML.load r.body[0]
+ ly = File.join Node1.app.layout_base_path, 'main.spec'
+ vu = File.join Node1.app.view_base_path, Node1.r, 'index.spec'
+ expect(h[:path]).to eq ly
+ expect(h[:layout]).to eq ly
+ expect(h[:view]).to eq vu
+ end
+
+ it 'before_all hook should work' do
+ Node3.before = 0
+ Node3.after = 0
+ expect(Node3.before).to eq 0
+ expect(Node3.my_call_i('/index')).to eq 1
+ expect(Node3.before).to eq 1
+ expect(Node3.my_call_i('/index')).to eq 1
+ expect(Node3.before).to eq 2
+ expect(Node3.my_call_i('/index')).to eq 1
+ expect(Node3.before).to eq 3
+ end
+
+ it 'after_all hook should work' do
+ Node3.before = 0
+ Node3.after = 0
+ expect(Node3.after).to eq 0
+ expect(Node3.my_call_i('/index')).to eq 1
+ expect(Node3.after).to eq 1
+ expect(Node3.my_call_i('/index')).to eq 1
+ expect(Node3.after).to eq 2
+ expect(Node3.my_call_i('/index')).to eq 1
+ expect(Node3.after).to eq 3
+ end
+
+ it 'inherited before_all hook should work' do
+ Node3.before = 0
+ Node3.after = 0
+ expect(Node3.before).to eq 0
+ expect(Node8.my_call_i('/index')).to eq 1
+ expect(Node3.before).to eq 1
+ expect(Node8.my_call_i('/index')).to eq 1
+ expect(Node3.before).to eq 2
+ expect(Node8.my_call_i('/index')).to eq 1
+ expect(Node3.before).to eq 3
+ end
+
+ it 'inherited after_all hook should work' do
+ Node3.before = 0
+ Node3.after = 0
+ expect(Node3.after).to eq 0
+ expect(Node8.my_call_i('/index')).to eq 1
+ expect(Node3.after).to eq 1
+ expect(Node8.my_call_i('/index')).to eq 1
+ expect(Node3.after).to eq 2
+ expect(Node8.my_call_i('/index')).to eq 1
+ expect(Node3.after).to eq 3
+ end
+
+ it 'should find view and layout and render them' do
+ r = Node0.my_call '/do_render'
+ expect(r.status).to eq 200
+ expect(r.body[0]).to eq 'layout_start view_content layout_end'
+ end
+
+ it 'default mime-type should be text/html' do
+ r = Node0.my_call '/index'
+ expect(r.headers['Content-type']).to eq 'text/html'
+ end
+
+ it 'should be able to override mime-type' do
+ r = Node0.my_call '/do_render'
+ expect(r.headers['Content-type']).to eq 'text/view'
+ end
+
+ it 'should be able to override through rack response mime-type' do
+ r = Node0.my_call '/do_content_type'
+ expect(r.headers['Content-type']).to eq 'text/mine'
+ end
+
+ it 'partial should render correctly' do
+ expect(Node0.partial({}, :do_partial, 1, 2)).to eq 'partial_content'
+ end
+
+ it 'method level view should work' do
+ expect(Node0.partial({}, :other_view)).to eq 'partial_content'
+ end
+
+ it 'partial with hooks should be default' do
+ Node3.before = 0
+ Node3.after = 0
+ expect(Node3.partial({}, :do_partial, 1, 2)).to eq 'partial_content'
+ expect(Node3.before).to eq 1
+ expect(Node3.after).to eq 1
+ end
- describe Zorglub::Node do
-
- before(:all) do
- clean_static_path
- end
-
- after(:all) do
- clean_static_path
- end
-
- it "engine should return default Node's engine" do
- expect(Node0.engine).to eq Node0.app.opt(:engine)
- end
-
- it "layout should return default Node's layout" do
- expect(Node0.layout).to eq Node0.app.opt(:layout)
- end
-
- it "engine should return class defined Node's engine" do
- expect(Node1.engine).to eq "engine-1"
- expect(Node3.engine).to eq "engine-2"
- end
-
- it "layout should return class defined Node's layout" do
- expect(Node1.layout).to eq "layout-1"
- expect(Node3.layout).to eq "layout-2"
- end
-
- it "engine should return engine inherited from Node2" do
- expect(Node2.engine).to eq "engine-1"
- end
-
- it "layout should return layout inherited from Node2" do
- expect(Node2.layout).to eq "layout-1"
- end
-
- it "r should build a well formed path" do
- expect(Node1.r(1,'arg2',"some")).to eq "/node1/1/arg2/some"
- end
-
- it "instance level map should work" do
- r = Node0.my_call '/with_2args/1/2'
- h = YAML.load r.body[0]
- expect(h[:map]).to eq '/node0'
- end
-
- it "should return err404 response when no method found" do
- expect(Node0.respond_to?('noresponse')).to be_falsey
- r = Node0.my_call '/noresponse'
- expect(r.status).to eq 404
- end
-
- it "simple method should respond" do
- r = Node0.my_call '/hello'
- expect(r.status).to eq 200
- expect(r.body[0]).to eq 'world'
- end
-
- it "instance level args should work" do
- r = Node0.my_call '/with_2args/1/2'
- h = YAML.load r.body[0]
- expect(h[:args][0]).to eq '1'
- expect(h[:args][1]).to eq '2'
- end
-
- it "should raise error when too much arguments" do
- expect(lambda{ r = Node0.my_call '/with_2args/1/2/3' }).to raise_error ArgumentError
- end
-
- it "layout proc, method level layout and engine definitions should work" do
- r = Node0.my_call '/index'
- expect(r.status).to eq 200
- h = YAML.load r.body[0]
- ly = File.join Node0.app.layout_base_path, Node0.layout
- vu = File.join Node0.app.view_base_path, Node0.r, 'index'
- expect(h[:path]).to eq ly
- expect(h[:layout]).to eq ly
- expect(h[:view]).to eq vu
- end
-
- it "layout proc, method level layout and engine definitions should work" do
- r = Node1.my_call '/index'
- expect(r.status).to eq 200
- h = YAML.load r.body[0]
- ly = File.join Node1.app.layout_base_path, 'main.spec'
- vu = File.join Node1.app.view_base_path, Node1.r, 'index.spec'
- expect(h[:path]).to eq ly
- expect(h[:layout]).to eq ly
- expect(h[:view]).to eq vu
- end
-
- it "before_all hook should work" do
- Node3.before = 0
- Node3.after = 0
- expect(Node3.before).to eq 0
- expect(Node3.my_call_i('/index')).to eq 1
- expect(Node3.before).to eq 1
- expect(Node3.my_call_i('/index')).to eq 1
- expect(Node3.before).to eq 2
- expect(Node3.my_call_i('/index')).to eq 1
- expect(Node3.before).to eq 3
- end
-
- it "after_all hook should work" do
- Node3.before = 0
- Node3.after = 0
- expect(Node3.after).to eq 0
- expect(Node3.my_call_i('/index')).to eq 1
- expect(Node3.after).to eq 1
- expect(Node3.my_call_i('/index')).to eq 1
- expect(Node3.after).to eq 2
- expect(Node3.my_call_i('/index')).to eq 1
- expect(Node3.after).to eq 3
- end
-
- it "inherited before_all hook should work" do
- Node3.before = 0
- Node3.after = 0
- expect(Node3.before).to eq 0
- expect(Node8.my_call_i('/index')).to eq 1
- expect(Node3.before).to eq 1
- expect(Node8.my_call_i('/index')).to eq 1
- expect(Node3.before).to eq 2
- expect(Node8.my_call_i('/index')).to eq 1
- expect(Node3.before).to eq 3
- end
-
- it "inherited after_all hook should work" do
- Node3.before = 0
- Node3.after = 0
- expect(Node3.after).to eq 0
- expect(Node8.my_call_i('/index')).to eq 1
- expect(Node3.after).to eq 1
- expect(Node8.my_call_i('/index')).to eq 1
- expect(Node3.after).to eq 2
- expect(Node8.my_call_i('/index')).to eq 1
- expect(Node3.after).to eq 3
- end
-
- it "should find view and layout and render them" do
- r = Node0.my_call '/do_render'
- expect(r.status).to eq 200
- expect(r.body[0]).to eq "layout_start view_content layout_end"
- end
-
- it "default mime-type should be text/html" do
- r = Node0.my_call '/index'
- expect(r.headers['Content-type']).to eq 'text/html'
- end
-
- it "should be able to override mime-type" do
- r = Node0.my_call '/do_render'
- expect(r.headers['Content-type']).to eq 'text/view'
- end
-
- it "should be able to override through rack response mime-type" do
- r = Node0.my_call '/do_content_type'
- expect(r.headers['Content-type']).to eq 'text/mine'
- end
-
- it "partial should render correctly" do
- expect(Node0.partial({},:do_partial, 1, 2)).to eq 'partial_content'
- end
-
- it "method level view should work" do
- expect(Node0.partial({},:other_view)).to eq 'partial_content'
- end
-
- it "partial with hooks should be default" do
- Node3.before = 0
- Node3.after = 0
- expect(Node3.partial({},:do_partial,1,2)).to eq 'partial_content'
- expect(Node3.before).to eq 1
- expect(Node3.after).to eq 1
- end
-
- it "partial without hooks should work" do
- Node3.before = 0
- Node3.after = 0
- expect(Node3.partial({:no_hooks=>true},:do_partial,1,2)).to eq 'partial_content'
- expect(Node3.before).to eq 0
- expect(Node3.after).to eq 0
- end
-
- it "static pages should be generated" do
- r = Node6.my_call '/do_static'
- expect(r.body[0]).to eq 'VAL 1'
- expect(r.headers['Content-type']).to eq 'text/static'
- r = Node6.my_call '/do_static'
- expect(r.body[0]).to eq 'VAL 1'
- expect(r.headers['Content-type']).to eq 'text/static'
- r = Node6.my_call '/do_static'
- expect(r.body[0]).to eq 'VAL 1'
- expect(r.headers['Content-type']).to eq 'text/static'
- r = Node6.my_call '/no_static'
- expect(r.body[0]).to eq 'VAL 4'
- expect(r.headers['Content-type']).to eq 'text/static'
- r = Node6.my_call '/do_static'
- expect(r.body[0]).to eq 'VAL 1'
- expect(r.headers['Content-type']).to eq 'text/static'
- Node6.static! true, 0.000001
- sleep 0.0001
- r = Node6.my_call '/do_static'
- expect(r.body[0]).to eq 'VAL 6'
- expect(r.headers['Content-type']).to eq 'text/static'
- end
-
- it "redirect should work" do
- r = Node0.my_call '/do_redirect'
- expect(r.status).to eq 302
- expect(r.headers['location']).to eq Node0.r(:do_partial,1,2,3)
- end
-
- it "no_layout! should be inherited" do
- expect(Node5.layout).to be_nil
- end
-
- it "cli_vals should be inherited and extended" do
- r = Node5.my_call '/index'
- vars = YAML.load r.body[0]
- expect(vars).to eq ['js0','js1','js3','jsx','css0','css1','css2']
- expect(vars[7]).to be_nil
- end
-
- it "cli_vals should be extended at method level" do
- r = Node4.my_call '/more'
- vars = YAML.load r.body[0]
- expect(vars).to eq ['js0','js1','js2']
- expect(vars[3]).to be_nil
- end
-
- it "cli_vals should be untouched" do
- r = Node4.my_call '/index'
- vars = YAML.load r.body[0]
- expect(vars).to eq ['js0','js1']
- expect(vars[2]).to be_nil
- r = Node5.my_call '/index'
- vars = YAML.load r.body[0]
- expect(vars).to eq ['js0','js1','js3','jsx','css0','css1','css2']
- expect(vars[7]).to be_nil
- end
-
- it "ext definition and file engine should work" do
- r = Node0.my_call '/xml_file'
- expect(r.body[0]).to eq "<xml>file<\/xml>\n"
- expect(r.headers['Content-type']).to eq 'application/xml'
- r = Node0.my_call '/plain_file'
- expect(r.body[0]).to eq "plain file\n"
- expect(r.headers['Content-type']).to eq 'text/plain'
- end
-
- it "no view no layout should work as well" do
- r = Node0.my_call '/no_view_no_layout'
- expect(r.body[0]).to eq "hello world"
- end
-
- it "haml engine should work" do
- Node0.app.opt! :engines_cache_enabled, false
- r = Node0.my_call '/engines/haml'
- expect(r.body[0]).to eq "<h1>Hello world</h1>\n"
- Node0.app.opt! :engines_cache_enabled, true
- r = Node0.my_call '/engines/haml'
- expect(r.body[0]).to eq "<h1>Hello world</h1>\n"
- end
-
- it "sass engine should work" do
- Node0.app.opt! :engines_cache_enabled, true
- r = Node0.my_call '/engines/sass'
- expect(r.body[0]).to eq "vbar{width:80%;height:23px}vbar ul{list-style-type:none}vbar li{float:left}vbar li a{font-weight:bold}\n"
- Node0.app.opt! :engines_cache_enabled, false
- r = Node0.my_call '/engines/sass'
- expect(r.body[0]).to eq "vbar{width:80%;height:23px}vbar ul{list-style-type:none}vbar li{float:left}vbar li a{font-weight:bold}\n"
- end
-
- it "view_base_path! should work" do
- r = Node7.my_call '/view_path'
- h = YAML.load r.body[0]
- expect(h[:view]).to eq File.join(Node7.app.opt(:root), 'alt','do_render')
- end
-
- it "layout_base_path! should work" do
- r = Node7.my_call '/view_path'
- h = YAML.load r.body[0]
- expect(h[:layout]).to eq File.join(Node7.app.opt(:root), 'alt','layout','default')
- end
-
- it "debug out should work" do
- stderr0= $stderr.dup
- stderrs = StringIO.new
- $stderr = stderrs
- begin
- APP.opt! :debug, true
- Node0.my_call '/hello'
- ensure
- $stderr = stderr0
- end
- expect(stderrs.string.include?('spec/data/view/node0/hello')).to be true
- end
+ it 'partial without hooks should work' do
+ Node3.before = 0
+ Node3.after = 0
+ expect(Node3.partial({ no_hooks: true }, :do_partial, 1, 2)).to eq 'partial_content'
+ expect(Node3.before).to eq 0
+ expect(Node3.after).to eq 0
+ end
+
+ it 'static pages should be generated' do
+ r = Node6.my_call '/do_static'
+ expect(r.body[0]).to eq 'VAL 1'
+ expect(r.headers['Content-type']).to eq 'text/static'
+ r = Node6.my_call '/do_static'
+ expect(r.body[0]).to eq 'VAL 1'
+ expect(r.headers['Content-type']).to eq 'text/static'
+ r = Node6.my_call '/do_static'
+ expect(r.body[0]).to eq 'VAL 1'
+ expect(r.headers['Content-type']).to eq 'text/static'
+ r = Node6.my_call '/no_static'
+ expect(r.body[0]).to eq 'VAL 4'
+ expect(r.headers['Content-type']).to eq 'text/static'
+ r = Node6.my_call '/do_static'
+ expect(r.body[0]).to eq 'VAL 1'
+ expect(r.headers['Content-type']).to eq 'text/static'
+ Node6.static! true, 0.000001
+ sleep 0.0001
+ r = Node6.my_call '/do_static'
+ expect(r.body[0]).to eq 'VAL 6'
+ expect(r.headers['Content-type']).to eq 'text/static'
+ end
+
+ it 'redirect should work' do
+ r = Node0.my_call '/do_redirect'
+ expect(r.status).to eq 302
+ expect(r.headers['location']).to eq Node0.r(:do_partial, 1, 2, 3)
+ end
+ it 'no_layout! should be inherited' do
+ expect(Node5.layout).to be_nil
end
+ it 'cli_vals should be inherited and extended' do
+ r = Node5.my_call '/index'
+ vars = YAML.load r.body[0]
+ expect(vars).to eq %w[js0 js1 js3 jsx css0 css1 css2]
+ expect(vars[7]).to be_nil
+ end
+
+ it 'cli_vals should be extended at method level' do
+ r = Node4.my_call '/more'
+ vars = YAML.load r.body[0]
+ expect(vars).to eq %w[js0 js1 js2]
+ expect(vars[3]).to be_nil
+ end
+
+ it 'cli_vals should be untouched' do
+ r = Node4.my_call '/index'
+ vars = YAML.load r.body[0]
+ expect(vars).to eq %w[js0 js1]
+ expect(vars[2]).to be_nil
+ r = Node5.my_call '/index'
+ vars = YAML.load r.body[0]
+ expect(vars).to eq %w[js0 js1 js3 jsx css0 css1 css2]
+ expect(vars[7]).to be_nil
+ end
+
+ it 'ext definition and file engine should work' do
+ r = Node0.my_call '/xml_file'
+ expect(r.body[0]).to eq "<xml>file<\/xml>\n"
+ expect(r.headers['Content-type']).to eq 'application/xml'
+ r = Node0.my_call '/plain_file'
+ expect(r.body[0]).to eq "plain file\n"
+ expect(r.headers['Content-type']).to eq 'text/plain'
+ end
+
+ it 'no view no layout should work as well' do
+ r = Node0.my_call '/no_view_no_layout'
+ expect(r.body[0]).to eq 'hello world'
+ end
+
+ it 'haml engine should work' do
+ Node0.app.opt! :engines_cache_enabled, false
+ r = Node0.my_call '/engines/haml'
+ expect(r.body[0]).to eq "<h1>Hello world</h1>\n"
+ Node0.app.opt! :engines_cache_enabled, true
+ r = Node0.my_call '/engines/haml'
+ expect(r.body[0]).to eq "<h1>Hello world</h1>\n"
+ end
+
+ it 'sass engine should work' do
+ Node0.app.opt! :engines_cache_enabled, true
+ r = Node0.my_call '/engines/sass'
+ expect(r.body[0]).to eq "vbar{width:80%;height:23px}vbar ul{list-style-type:none}vbar li{float:left}vbar li a{font-weight:bold}\n"
+ Node0.app.opt! :engines_cache_enabled, false
+ r = Node0.my_call '/engines/sass'
+ expect(r.body[0]).to eq "vbar{width:80%;height:23px}vbar ul{list-style-type:none}vbar li{float:left}vbar li a{font-weight:bold}\n"
+ end
+
+ it 'view_base_path! should work' do
+ r = Node7.my_call '/view_path'
+ h = YAML.load r.body[0]
+ expect(h[:view]).to eq File.join(Node7.app.opt(:root), 'alt', 'do_render')
+ end
+
+ it 'layout_base_path! should work' do
+ r = Node7.my_call '/view_path'
+ h = YAML.load r.body[0]
+ expect(h[:layout]).to eq File.join(Node7.app.opt(:root), 'alt', 'layout', 'default')
+ end
+
+ it 'debug out should work' do
+ stderr0 = $stderr.dup
+ stderrs = StringIO.new
+ $stderr = stderrs
+ begin
+ APP.opt! :debug, true
+ Node0.my_call '/hello'
+ ensure
+ $stderr = stderr0
+ end
+ expect(stderrs.string.include?('spec/data/view/node0/hello')).to be true
+ end
+ end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 9b2c452..257327e 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,19 +1,19 @@
#! /usr/bin/env ruby
begin
- require 'simplecov'
- SimpleCov.start do
- add_filter 'spec'
- end
+ require 'simplecov'
+ SimpleCov.start do
+ add_filter 'spec'
+ end
rescue LoadError
end
begin
- require 'coveralls'
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new [
- SimpleCov::Formatter::HTMLFormatter,
- Coveralls::SimpleCov::Formatter
- ]
+ require 'coveralls'
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new [
+ SimpleCov::Formatter::HTMLFormatter,
+ Coveralls::SimpleCov::Formatter
+ ]
rescue LoadError
end
@@ -24,206 +24,223 @@ require 'zorglub/engines/file'
require 'zorglub/engines/haml'
require 'zorglub/engines/sass'
-HASH_PROC = Proc.new { |path,obj| {:path=>path,:layout=>obj.layout,:view=>obj.view,:args=>obj.args,:map=>obj.map}.to_yaml }
-STATIC_PROC = Proc.new { |path,obj| ["VAL #{obj.value}",'text/static'] }
-RENDER_PROC = Proc.new { |path,obj|
- case obj.state
- when :layout
- "layout_start #{obj.content} layout_end"
- when :view
- ["view_content", 'text/view']
- when :partial
- ['partial_content','text/partial']
- else
- raise Exception.new
- end
+HASH_PROC = proc { |path, obj| { path: path, layout: obj.layout, view: obj.view, args: obj.args, map: obj.map }.to_yaml }
+STATIC_PROC = proc { |_path, obj| ["VAL #{obj.value}", 'text/static'] }
+RENDER_PROC = proc { |_path, obj|
+ case obj.state
+ when :layout
+ "layout_start #{obj.content} layout_end"
+ when :view
+ ['view_content', 'text/view']
+ when :partial
+ ['partial_content', 'text/partial']
+ else
+ raise Exception.new
+ end
}
APP_ROOT = File.join Dir.pwd, 'spec', 'data'
class Zorglub::Node
- def self.my_call uri
- call( {'PATH_INFO'=>uri} )
- end
- def self.my_call_i uri
- call( {'PATH_INFO'=>uri} ).body[0].to_i
- end
+ def self.my_call(uri)
+ call({ 'PATH_INFO' => uri })
+ end
+
+ def self.my_call_i(uri)
+ call({ 'PATH_INFO' => uri }).body[0].to_i
+ end
end
class Temp < Zorglub::Node
end
class Node0 < Zorglub::Node
- # default
- def index
- html
- end
- def hello
- no_layout!
- 'world'
- end
- def with_2args a1, a2
- end
- def do_render
- engine! 'real'
- end
- def do_content_type
- engine! 'real'
- response.headers['Content-Type'] = 'text/mine'
- end
- def do_partial a1, a2
- engine! 'real'
- end
- def other_view
- engine! 'real'
- view! r('do_partial')
- end
- def do_redirect
- redirect r(:do_partial,1,2,3)
- end
- def xml_file
- no_layout!
- engine! :file
- ext! 'xml'
- mime! 'application/xml'
- end
- def plain_file
- no_layout!
- engine! :file
- ext! 'txt'
- mime! 'text/plain'
- end
- def no_view_no_layout
- no_view!
- no_layout!
- 'hello world'
- end
- def engines name
- no_layout!
- case name
- when 'haml'
- engine! :haml
- when 'sass'
- engine! :sass
- end
+ # default
+ def index
+ html
+ end
+
+ def hello
+ no_layout!
+ 'world'
+ end
+
+ def with_2args(arg1, arg2); end
+
+ def do_render
+ engine! 'real'
+ end
+
+ def do_content_type
+ engine! 'real'
+ response.headers['Content-Type'] = 'text/mine'
+ end
+
+ def do_partial(_arg1, _arg2)
+ engine! 'real'
+ end
+
+ def other_view
+ engine! 'real'
+ view! r('do_partial')
+ end
+
+ def do_redirect
+ redirect r(:do_partial, 1, 2, 3)
+ end
+
+ def xml_file
+ no_layout!
+ engine! :file
+ ext! 'xml'
+ mime! 'application/xml'
+ end
+
+ def plain_file
+ no_layout!
+ engine! :file
+ ext! 'txt'
+ mime! 'text/plain'
+ end
+
+ def no_view_no_layout
+ no_view!
+ no_layout!
+ 'hello world'
+ end
+
+ def engines(name)
+ no_layout!
+ case name
+ when 'haml'
+ engine! :haml
+ when 'sass'
+ engine! :sass
end
+ end
end
class Node1 < Zorglub::Node
- layout! 'layout-1'
- engine! 'engine-1'
- def index
- layout! 'main'
- engine! 'engine-2'
- end
+ layout! 'layout-1'
+ engine! 'engine-1'
+ def index
+ layout! 'main'
+ engine! 'engine-2'
+ end
end
class Node2 < Node1
- # inherited from Node1
+ # inherited from Node1
end
class Node3 < Zorglub::Node
- @before=0
- @after=0
- class << self
- attr_accessor :before, :after
- def post obj
- @after +=1
- end
- end
- before_all do |node|
- Node3.before +=1
- end
- after_all Node3.method(:post)
- layout! 'layout-2'
- engine! 'engine-2'
- def index
- Node3.before-Node3.after
- end
- def do_partial a1, a2
- view! Node0.r('do_partial')
- engine! 'real'
- end
+ @before = 0
+ @after = 0
+ class << self
+ attr_accessor :before, :after
+
+ def post(_obj)
+ @after += 1
+ end
+ end
+ before_all do |_node|
+ Node3.before += 1
+ end
+ after_all Node3.method(:post)
+ layout! 'layout-2'
+ engine! 'engine-2'
+ def index
+ Node3.before - Node3.after
+ end
+
+ def do_partial(_arg1, _arg2)
+ view! Node0.r('do_partial')
+ engine! 'real'
+ end
end
class Node8 < Node3
end
class Node4 < Zorglub::Node
- no_layout!
- cli_val :js,'js0'
- cli_val :js,'js1'
- def index
- cli_val(:js).to_yaml
- end
- def more
- cli_val :js,'js2'
- cli_val(:js).to_yaml
- end
+ no_layout!
+ cli_val :js, 'js0'
+ cli_val :js, 'js1'
+
+ def index
+ cli_val(:js).to_yaml
+ end
+
+ def more
+ cli_val :js, 'js2'
+ cli_val(:js).to_yaml
+ end
end
class Node5 < Node4
- cli_val :js, 'js3'
- cli_val :css, 'css0', 'css1'
- # no_layout! inherited from Node4
- def index
- js = cli_val(:js,'jsx')
- cli_val(:css, 'css0', 'css1','css2')
- css = cli_val :css
- js.concat(css).to_yaml
- end
+ cli_val :js, 'js3'
+ cli_val :css, 'css0', 'css1'
+ # no_layout! inherited from Node4
+ def index
+ js = cli_val(:js, 'jsx')
+ cli_val(:css, 'css0', 'css1', 'css2')
+ css = cli_val :css
+ js.concat(css).to_yaml
+ end
end
class Node6 < Zorglub::Node
- @static_cpt=0
- class << self
- attr_accessor :static_cpt
- end
- attr_reader :value
- static! true, 5
- def no_static
- static! false
- engine! 'static'
- view! Node0.r('do_render')
- Node6.static_cpt+=1
- @value = Node6.static_cpt
- end
- def do_static
- engine! 'static'
- view! Node0.r('do_render')
- Node6.static_cpt+=1
- @value = Node6.static_cpt
- end
+ @static_cpt = 0
+ class << self
+ attr_accessor :static_cpt
+ end
+ attr_reader :value
+
+ static! true, 5
+ def no_static
+ static! false
+ engine! 'static'
+ view! Node0.r('do_render')
+ Node6.static_cpt += 1
+ @value = Node6.static_cpt
+ end
+
+ def do_static
+ engine! 'static'
+ view! Node0.r('do_render')
+ Node6.static_cpt += 1
+ @value = Node6.static_cpt
+ end
end
class Node7 < Zorglub::Node
- layout_base_path! File.join APP_ROOT, 'alt','layout'
- view_base_path! File.join APP_ROOT, 'alt'
- def view_path
- view! 'do_render'
- end
+ layout_base_path! File.join APP_ROOT, 'alt', 'layout'
+ view_base_path! File.join APP_ROOT, 'alt'
+ def view_path
+ view! 'do_render'
+ end
end
APP = Zorglub::App.new do
- register_engine! :file, nil, Zorglub::Engines::File.method(:proc)
- register_engine! :haml, 'haml', Zorglub::Engines::Haml.method(:proc)
- register_engine! :sass, 'scss', Zorglub::Engines::Sass.method(:proc)
- register_engine! 'default', nil, HASH_PROC
- register_engine! 'engine-1', 'spec', HASH_PROC
- register_engine! 'engine-2', 'spec', HASH_PROC
- register_engine! 'real', nil, RENDER_PROC
- register_engine! 'static', nil, STATIC_PROC
- opt! :root, APP_ROOT
- opt! :engine, 'default'
- map '/node0', Node0
- map '/node1', Node1
- map '/node3', Node3
- map '/node4', Node4
- map '/node5', Node5
- map '/node6', Node6
- map '/node7', Node7
- map '/node8', Node8
+ register_engine! :file, nil, Zorglub::Engines::File.method(:proc)
+ register_engine! :haml, 'haml', Zorglub::Engines::Haml.method(:proc)
+ register_engine! :sass, 'scss', Zorglub::Engines::Sass.method(:proc)
+ register_engine! 'default', nil, HASH_PROC
+ register_engine! 'engine-1', 'spec', HASH_PROC
+ register_engine! 'engine-2', 'spec', HASH_PROC
+ register_engine! 'real', nil, RENDER_PROC
+ register_engine! 'static', nil, STATIC_PROC
+ opt! :root, APP_ROOT
+ opt! :engine, 'default'
+ map '/node0', Node0
+ map '/node1', Node1
+ map '/node3', Node3
+ map '/node4', Node4
+ map '/node5', Node5
+ map '/node6', Node6
+ map '/node7', Node7
+ map '/node8', Node8
end
class Node2
- map APP, '/node2'
+ map APP, '/node2'
end