Checkout of Instiki Trunk 1/21/2007.
This commit is contained in:
commit
69b62b6f33
1138 changed files with 139586 additions and 0 deletions
235
vendor/rails/actionpack/lib/action_controller/code_generation.rb
vendored
Normal file
235
vendor/rails/actionpack/lib/action_controller/code_generation.rb
vendored
Normal file
|
@ -0,0 +1,235 @@
|
|||
module ActionController
|
||||
module CodeGeneration #:nodoc:
|
||||
class GenerationError < StandardError #:nodoc:
|
||||
end
|
||||
|
||||
class Source #:nodoc:
|
||||
attr_reader :lines, :indentation_level
|
||||
IndentationString = ' '
|
||||
def initialize
|
||||
@lines, @indentation_level = [], 0
|
||||
end
|
||||
def line(line)
|
||||
@lines << (IndentationString * @indentation_level + line)
|
||||
end
|
||||
alias :<< :line
|
||||
|
||||
def indent
|
||||
@indentation_level += 1
|
||||
yield
|
||||
ensure
|
||||
@indentation_level -= 1
|
||||
end
|
||||
|
||||
def to_s() lines.join("\n") end
|
||||
end
|
||||
|
||||
class CodeGenerator #:nodoc:
|
||||
attr_accessor :source, :locals
|
||||
def initialize(source = nil)
|
||||
@locals = []
|
||||
@source = source || Source.new
|
||||
end
|
||||
|
||||
BeginKeywords = %w(if unless begin until while def).collect {|kw| kw.to_sym}
|
||||
ResumeKeywords = %w(elsif else rescue).collect {|kw| kw.to_sym}
|
||||
Keywords = BeginKeywords + ResumeKeywords
|
||||
|
||||
def method_missing(keyword, *text)
|
||||
if Keywords.include? keyword
|
||||
if ResumeKeywords.include? keyword
|
||||
raise GenerationError, "Can only resume with #{keyword} immediately after an end" unless source.lines.last =~ /^\s*end\s*$/
|
||||
source.lines.pop # Remove the 'end'
|
||||
end
|
||||
|
||||
line "#{keyword} #{text.join ' '}"
|
||||
begin source.indent { yield(self.dup) }
|
||||
ensure line 'end'
|
||||
end
|
||||
else
|
||||
super(keyword, *text)
|
||||
end
|
||||
end
|
||||
|
||||
def line(*args) self.source.line(*args) end
|
||||
alias :<< :line
|
||||
def indent(*args, &block) source(*args, &block) end
|
||||
def to_s() source.to_s end
|
||||
|
||||
def share_locals_with(other)
|
||||
other.locals = self.locals = (other.locals | locals)
|
||||
end
|
||||
|
||||
FieldsToDuplicate = [:locals]
|
||||
def dup
|
||||
copy = self.class.new(source)
|
||||
self.class::FieldsToDuplicate.each do |sym|
|
||||
value = self.send(sym)
|
||||
value = value.dup unless value.nil? || value.is_a?(Numeric)
|
||||
copy.send("#{sym}=", value)
|
||||
end
|
||||
return copy
|
||||
end
|
||||
end
|
||||
|
||||
class RecognitionGenerator < CodeGenerator #:nodoc:
|
||||
Attributes = [:after, :before, :current, :results, :constants, :depth, :move_ahead, :finish_statement]
|
||||
attr_accessor(*Attributes)
|
||||
FieldsToDuplicate = CodeGenerator::FieldsToDuplicate + Attributes
|
||||
|
||||
def initialize(*args)
|
||||
super(*args)
|
||||
@after, @before = [], []
|
||||
@current = nil
|
||||
@results, @constants = {}, {}
|
||||
@depth = 0
|
||||
@move_ahead = nil
|
||||
@finish_statement = Proc.new {|hash_expr| hash_expr}
|
||||
end
|
||||
|
||||
def if_next_matches(string, &block)
|
||||
test = Routing.test_condition(next_segment(true), string)
|
||||
self.if(test, &block)
|
||||
end
|
||||
|
||||
def move_forward(places = 1)
|
||||
dup = self.dup
|
||||
dup.depth += 1
|
||||
dup.move_ahead = places
|
||||
yield dup
|
||||
end
|
||||
|
||||
def next_segment(assign_inline = false, default = nil)
|
||||
if locals.include?(segment_name)
|
||||
code = segment_name
|
||||
else
|
||||
code = "#{segment_name} = #{path_name}[#{index_name}]"
|
||||
if assign_inline
|
||||
code = "(#{code})"
|
||||
else
|
||||
line(code)
|
||||
code = segment_name
|
||||
end
|
||||
|
||||
locals << segment_name
|
||||
end
|
||||
code = "(#{code} || #{default.inspect})" if default
|
||||
|
||||
return code.to_s
|
||||
end
|
||||
|
||||
def segment_name() "segment#{depth}".to_sym end
|
||||
def path_name() :path end
|
||||
def index_name
|
||||
move_ahead, @move_ahead = @move_ahead, nil
|
||||
move_ahead ? "index += #{move_ahead}" : 'index'
|
||||
end
|
||||
|
||||
def continue
|
||||
dup = self.dup
|
||||
dup.before << dup.current
|
||||
dup.current = dup.after.shift
|
||||
dup.go
|
||||
end
|
||||
|
||||
def go
|
||||
if current then current.write_recognition(self)
|
||||
else self.finish
|
||||
end
|
||||
end
|
||||
|
||||
def result(key, expression, delay = false)
|
||||
unless delay
|
||||
line "#{key}_value = #{expression}"
|
||||
expression = "#{key}_value"
|
||||
end
|
||||
results[key] = expression
|
||||
end
|
||||
def constant_result(key, object)
|
||||
constants[key] = object
|
||||
end
|
||||
|
||||
def finish(ensure_traversal_finished = true)
|
||||
pairs = []
|
||||
(results.keys + constants.keys).uniq.each do |key|
|
||||
pairs << "#{key.to_s.inspect} => #{results[key] ? results[key] : constants[key].inspect}"
|
||||
end
|
||||
hash_expr = "{#{pairs.join(', ')}}"
|
||||
|
||||
statement = finish_statement.call(hash_expr)
|
||||
if ensure_traversal_finished then self.if("! #{next_segment(true)}") {|gp| gp << statement}
|
||||
else self << statement
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class GenerationGenerator < CodeGenerator #:nodoc:
|
||||
Attributes = [:after, :before, :current, :segments]
|
||||
attr_accessor(*Attributes)
|
||||
FieldsToDuplicate = CodeGenerator::FieldsToDuplicate + Attributes
|
||||
|
||||
def initialize(*args)
|
||||
super(*args)
|
||||
@after, @before = [], []
|
||||
@current = nil
|
||||
@segments = []
|
||||
end
|
||||
|
||||
def hash_name() 'hash' end
|
||||
def local_name(key) "#{key}_value" end
|
||||
|
||||
def hash_value(key, assign = true, default = nil)
|
||||
if locals.include?(local_name(key)) then code = local_name(key)
|
||||
else
|
||||
code = "hash[#{key.to_sym.inspect}]"
|
||||
if assign
|
||||
code = "(#{local_name(key)} = #{code})"
|
||||
locals << local_name(key)
|
||||
end
|
||||
end
|
||||
code = "(#{code} || (#{default.inspect}))" if default
|
||||
return code
|
||||
end
|
||||
|
||||
def expire_for_keys(*keys)
|
||||
return if keys.empty?
|
||||
conds = keys.collect {|key| "expire_on[#{key.to_sym.inspect}]"}
|
||||
line "not_expired, #{hash_name} = false, options if not_expired && #{conds.join(' && ')}"
|
||||
end
|
||||
|
||||
def add_segment(*segments)
|
||||
d = dup
|
||||
d.segments.concat segments
|
||||
yield d
|
||||
end
|
||||
|
||||
def go
|
||||
if current then current.write_generation(self)
|
||||
else self.finish
|
||||
end
|
||||
end
|
||||
|
||||
def continue
|
||||
d = dup
|
||||
d.before << d.current
|
||||
d.current = d.after.shift
|
||||
d.go
|
||||
end
|
||||
|
||||
def finish
|
||||
line %("/#{segments.join('/')}")
|
||||
end
|
||||
|
||||
def check_conditions(conditions)
|
||||
tests = []
|
||||
generator = nil
|
||||
conditions.each do |key, condition|
|
||||
tests << (generator || self).hash_value(key, true) if condition.is_a? Regexp
|
||||
tests << Routing.test_condition((generator || self).hash_value(key, false), condition)
|
||||
generator = self.dup unless generator
|
||||
end
|
||||
return tests.join(' && ')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue