pax_global_header 0000666 0000000 0000000 00000000064 11301254024 0014502 g ustar 00root root 0000000 0000000 52 comment=62bc0c33cabd5b72f36c93ed8f3ff55700f1be5d
amrita2-2.0.2+dfsg.1/ 0000775 0000000 0000000 00000000000 11301254024 0014120 5 ustar 00root root 0000000 0000000 amrita2-2.0.2+dfsg.1/README 0000664 0000000 0000000 00000005524 11301254024 0015006 0 ustar 00root root 0000000 0000000 = Amrita2 - a xml/xhtml template library for Ruby
== Summary
Amrita2 is a a xml/xhtml template library for Ruby.
It makes html documents from a template and a model data.
=== Key feature
specify "XML template" do
t = Amrita2::Template.new <<-END
is a html template library for
END
data = {
:page_title=>'Amrita2',
:header_title=>'Hello, Amrita2',
:text=>{
:template => 'Amrita2',
:lang => 'Ruby'
}
}
expected = <<-END
Amrita2
Hello, Amrita2
Amrita2 is a html template library for Ruby
END
#
t.render_with(data).should_be_samexml_as(expected)
t2 = Amrita2::Template.new <<-END
<>
<>
<
> is a html template library for <<:lang>>
END
#
t2.render_with(data).should_be_samexml_as(expected)
end
* The template for amrita2 is a pure html/xhtml document without no
special tag like ...?> or <% .. %>
* The template can be written by designers using almost any xhtml/xml
Editor.
* Need no change on Ruby code to change the view of _dynamic_ part
(not only static part) of the template
* The model data may be standard Ruby data, Hash, Array, String... or
an instance of a classes you made.
* The output is controlled by _data_ not by logic. So It's easy to
write, test, debug code. (Good for eXtreamPrograming)
Amrita2 mixes a template and model data up to a html document naturally
matching the +id+ attribute of XML element to model data.
=== Current version and roadmap
Current version is 2.0.2 .
=== Setup
# gem install amrita2
== document
Start spec/intro.rb or Amrita2 Wiki (http://retro.brain-tokyo.net/projects/amrita2/wiki/Amrita2)
== support/developement
* http://retro.brain-tokyo.net/projects/amrita2/blog
== Download
* http://rubyforge.org/projects/amrita2
== License
Amrita2 is Copyright (c) 2008 Taku Nakajima
. It is free software, and may be
redistributed under the terms specified in the README file of the Ruby
distribution.
Sample source code under sample/depot is Amrita2 version of
Depot Application of "Agile Web Development with Rails".
http://www.pragprog.com/titles/rails2/source_code
Sample source code under sample/login_engine is Amrita2 version of LoginEngine.
http://rails-engines.org/news/2007/01/23/farewell-login_engine-/
amrita2-2.0.2+dfsg.1/Rakefile 0000664 0000000 0000000 00000003467 11301254024 0015577 0 ustar 00root root 0000000 0000000 require 'rubygems'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'spec/rake/spectask'
require 'lib/amrita2/version'
Gem.manage_gems
TMP='/tmp'
PACKAGE_NAME = "amrita2"
PACKAGE_VERSION = Amrita2::Version::STRING
package_name = "#{PACKAGE_NAME}-#{PACKAGE_VERSION}"
package_dir = "pkg"
package_dir_path = "#{package_dir}/#{package_name}"
tar_file = "#{package_name}.tar.gz"
gem_file = "#{package_name}.gem"
ENV['RUBYLIB'] = "lib"
task :default => [ :specs, :test_login_engine, :spec1 ]
task :test => [ :specs ]
desc "Run all specs"
Spec::Rake::SpecTask.new('specs') do |t|
t.spec_files = FileList['specs/**/*.rb']
t.spec_opts = %w(-Du)
end
desc "Run all specs one by one"
task :spec1 do
tmp = "/tmp/amrita_spec.out"
Dir['specs/**/*.rb'].each do |f|
begin
sh %{spec #{f} > #{tmp} }
sh %{spec -r amrita2/gettext #{f} > #{tmp} }
rescue
puts File::open(tmp).read
raise
end
end
end
task :clean do
Dir['**/*~'].each do |f|
puts f
FileUtils::rm_f f
end
Dir['docs'].each do |f|
puts f
FileUtils::rm_rf f
end
end
task :test_login_engine do
Dir::chdir("sample/login_engine") do
Dir::mkdir "log" unless FileTest::directory?("log")
sh %{rake test}
end
end
desc "Generate documentation for the application"
Rake::RDocTask.new("appdoc") { |rdoc|
rdoc.rdoc_dir = 'docs/app'
rdoc.title = "Amrita2 Documentation"
rdoc.rdoc_files = Dir['lib/amrita2/*.rb']
rdoc.rdoc_files << 'README'
}
task :tar do
Dir::chdir(TMP) do
system 'rm -rf amrita2'
system "svn export http://svn.brain-tokyo.net/amrita2/trunk/amrita2 #{package_name}"
system "tar zcvf #{tar_file} #{package_name}"
end
end
task :gem => :clean do
spec = eval(File.read("amrita2.gemspec"))
Gem::Builder.new(spec).build
mv gem_file, "#{TMP}/#{gem_file}"
end
amrita2-2.0.2+dfsg.1/amrita2.gemspec 0000664 0000000 0000000 00000001226 11301254024 0017025 0 ustar 00root root 0000000 0000000 require 'lib/amrita2/version'
Gem::Specification.new do |s|
s.name = 'amrita2'
s.version = Amrita2::Version::STRING
s.platform = Gem::Platform::RUBY
s.summary =
"Amrita2 is a a xml/xhtml template library for Ruby"
s.files = Dir.glob("{lib,specs,sample}/**/*") << "README" << "Rakefile" << "init.rb"
s.require_path = 'lib'
s.homepage = 'http://retro.brain-tokyo.net/projects/amrita2/wiki/Amrita2'
s.rubyforge_project = 'amrita2'
s.has_rdoc=true
s.rdoc_options << "--main" << "README"
s.extra_rdoc_files = ["README"]
s.add_dependency('hpricot', '>= 0.6.0')
s.author = "Taku Nakajima"
s.email = "tnakajima@brain-tokyo.jp"
end
amrita2-2.0.2+dfsg.1/init.rb 0000664 0000000 0000000 00000000322 11301254024 0015405 0 ustar 00root root 0000000 0000000 # plugin init files for Ruby On Rails
require 'amrita2/rails_bridge'
ActionView::Base.register_template_handler "a2html", Amrita2View::Base
ActionView::Base.register_template_handler "a2", Amrita2View::Base
amrita2-2.0.2+dfsg.1/lib/ 0000775 0000000 0000000 00000000000 11301254024 0014666 5 ustar 00root root 0000000 0000000 amrita2-2.0.2+dfsg.1/lib/amrita2.rb 0000664 0000000 0000000 00000000065 11301254024 0016553 0 ustar 00root root 0000000 0000000 require 'amrita2/template'
require 'amrita2/version'
amrita2-2.0.2+dfsg.1/lib/amrita2/ 0000775 0000000 0000000 00000000000 11301254024 0016225 5 ustar 00root root 0000000 0000000 amrita2-2.0.2+dfsg.1/lib/amrita2/gettext.rb 0000664 0000000 0000000 00000005067 11301254024 0020246 0 ustar 00root root 0000000 0000000 require 'amrita2/template'
require 'gettext/rgettext'
module Amrita2
module Core
class CompoundElement # :nodoc: all
def get_erb_source
@children.collect do |c|
c.get_erb_source
end.join("\n")
end
end
class ErbNode # :nodoc: all
def get_erb_source
return @node.to_s
end
end
class DynamicElement # :nodoc: all
def get_erb_source
@children.collect do |c|
c.get_erb_source
end.join("\n")
end
end
class CommentNode # :nodoc: all
def get_erb_source
""
end
end
class RootElement < DynamicElement # :nodoc: all
attr_accessor :text_domain
compile_old = self.instance_method(:compile)
define_method(:compile) do |cg|
cg.code("bindtextdomain(#{@text_domain.inspect})")
compile_old.bind(self).call(cg)
end
end
class Template
attr_accessor :text_domain
def compile_for_gettext
setup
end
def get_erb_source_for_gettext
setup
@root.get_erb_source
end
end
end
module GetTextBridge # :nodoc: all
class TextNodeForGetText < Core::StaticNode
def dynamic?
true
end
def render_me(cg)
#text = @node.to_s.strip
# to keep
text = ""
@node.output(text, :preserve=>true)
text.strip!
cg.put_string_expression("_(#{text.inspect}) % $_") if text != ""
end
def get_erb_source
return ""
end
end
end
module Filters
class GetTextFilter < Filters::Base
def parse_node(de, node)
case node
when Hpricot::CData
super
when Hpricot::Text
Amrita2::GetTextBridge::TextNodeForGetText.new(de, node)
else
super
end
end
end
end
module GetTextParser # :nodoc: all
include Amrita2
include Amrita2::GetTextBridge
module_function
def target?(file)
File.extname(file) == '.a2html' || File.extname(file) == '.a2'
end
def parse(file, ary)
t = Template.new(File::open(file).read) do |e, src, filters|
filters << Filters::GetTextFilter.new
end
src = t.compile_for_gettext
RubyParser.parse_lines(file, [src], ary)
src = t.get_erb_source_for_gettext
erb = ERB.new(src).src.split(/$/)
RubyParser.parse_lines(file, erb, ary)
ary.collect do |msgid, fnameandline|
[msgid, fnameandline.gsub(/\d+$/, "-")]
end
end
end
end
GetText::RGetText.add_parser(Amrita2::GetTextParser)
amrita2-2.0.2+dfsg.1/lib/amrita2/macro.rb 0000664 0000000 0000000 00000007716 11301254024 0017666 0 ustar 00root root 0000000 0000000 require 'amrita2/template'
module Amrita2
class Core::Template
def add_macro(m)
@macros ||= []
@macros << m
end
alias use_macro add_macro
compile_old = instance_method(:compile)
define_method(:compile) do |*args|
macros = @macros
if macros and macros.size > 0
filter_setup do |e, name ,filters|
filters << MacroFilter.new(*macros)
end
end
compile_old.bind(self).call(*args)
end
end
module Macro # :nodoc: all
class Base
def initialize
@mt = Template.new(get_macro_template, :amrita_prefix=>"macro:", :inline_ruby=>true)
@option = {}
@option = self.class.const_get(:Option) if self.class.const_defined?(:Option)
raise "Macro Option is not defined propery in #{self.class} #{@option.inspect}" unless @option.kind_of?(Hash)
end
def get_macro_template
self.class.const_get(:TemplateText)
end
def get_element_name
#self.class.const_get(:ElementName)
@option[:tag] || underscore(self.class.name)
end
def process(de, element)
preprocess_element(@mt, element)
end
def match_element(element)
element.name == get_element_name.to_s
end
def macro_data(element)
element.as_amrita_dictionary(@option)
end
def preprocess_element(mt, element)
if @option[:trace]
mt.set_trace(@option[:trace])
@option[:trace] << (macro_data(element)).inspect
end
mt.amrita_prefix = "macro:"
mt.render_with(macro_data(element))
end
private
# from activesupport
def underscore(camel_cased_word)
camel_cased_word.to_s.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end
end
module Filters
class MacroFilter < Base
include Amrita2
include Util
include OptionSupport
attr_reader :macros
def initialize(*macros)
@macros = macros.collect do |m|
case m
when Class
m.new
else
m
end
end
@element_names = {}
@macros.each do |m|
@element_names[m.get_element_name.to_s] = true
end
end
def check_element(element)
return true if @element_names[element.name]
element.each_child do |c|
next unless c.kind_of?(Hpricot::Elem)
return true if @element_names[c.name] or check_element(c)
end
false
end
def filter_element(de, element)
return element unless check_element(element)
@macros.each do |m|
if m.match_element(element)
ret = m.process(de, element)
ret = Core::PreProcessor.new.process(ret.dup)
ret.gsub!('<%%', '<%')
ret.gsub!('%%>', '%>')
root = Hpricot.make("<_ />").first
Hpricot.make(ret, :xml=>true).each do |e|
root.insert_after(e, nil)
end
element = replace_target_src(root)
else
element.each_child do |c|
next unless c.kind_of?(Hpricot::Elem)
cc = filter_element(de, c)
element.replace_child(c, cc) if c != cc
end
end
end
element
end
def replace_target_src(e)
%w(src filter v skipif for).each do |k|
e.set_attribute("am:#{k}", e.attributes["target_#{k}"]) if e.attributes["target_#{k}"]
e.delete_attribute("target_#{k}")
end
e.each_child do |c|
next unless c.kind_of?(Hpricot::Elem)
replace_target_src(c)
end
e
end
def element_render_code(de, cg, element, &block)
if (element.name == 'macroroot')
yield
else
super
end
end
end
end
end
amrita2-2.0.2+dfsg.1/lib/amrita2/rails_bridge.rb 0000664 0000000 0000000 00000014572 11301254024 0021211 0 ustar 00root root 0000000 0000000 require 'amrita2/template'
require 'action_view'
module Amrita2
module Core
class Hook
include ActionView::Helpers::FormHelper
include ActionView::Helpers::FormHelper
end
end
end
module Amrita2View # :nodoc: all
module FormHelper
class FormFieldHelper
include Amrita2::DictionaryData
attr_reader :form, :data
def initialize(record, form, &block)
@record = record
@form = form
@data = {}
block.call(self)
end
def add_field(name, value)
@data[name] = value
end
def add_field_element(name, element)
add_field(name, Amrita2::SanitizedString[element])
end
def method_missing(meth, name, *args, &block)
value = @form.send(meth, name, *args, &block)
add_field_element(name, value)
end
def as_hash
@data
end
def as_label_field_hash
@data.inject(Hash.new) do |h, data|
k, v = *data
h.merge ({
k => {
:label => {
:for=>"#{@record}_#{k}",
:text=>k.to_s
},
:field => v
}
})
end
end
end
def amrita_define_form(*args, &block)
record = args.first
method = :form_for
format = :as_hash
case h = args.last
when Hash
method = h.delete(:form_method) || method
format = h.delete(:amrita_format) || format
end
amrita_form_hook(method, *args) do |f|
FormFieldHelper.new(record, f) do |ff|
block.call(ff)
end.send(format)
end
end
def amrita_form_hook(meth, *args, &block)
view = self
hook = Amrita2::Core::Hook.new do
_erbout = stream
view.instance_eval do
self.send(meth, *args) do |f|
data = block.call(f)
hook.render_me_with(data)
end
end
end
end
end
FormFieldHelper = FormHelper::FormFieldHelper
end
module ActionView # :nodoc: all
class Base #:nodoc:
include Amrita2::Runtime
include Amrita2View::FormHelper
end
end
module ActiveRecord # :nodoc: all
class Base
include Amrita2::DictionaryData
end
class ConnectionAdapters::Column
include Amrita2::DictionaryData
end
end
module Amrita2View # :nodoc: all
class Base
include Amrita2
include Amrita2::Filters
include Amrita2::Runtime
include Amrita2::Util
CompileTimeBinding = binding
@@compiled_amrita2_templates = {}
@@text_domain = nil
cattr_accessor :text_domain
def initialize( action_view )
@action_view = action_view
end
def render(template, local_assigns={})
Thread::current[:amrita_rails_view] = @action_view
if template.kind_of?(String)
render_amrita(template, local_assigns)
else
@action_view.render(template, local_assigns)
end
end
def setup_template(template)
setup_template_default(template)
end
def setup_template_default(template)
if Amrita2::const_defined?(:GetTextBridge)
t = Amrita2::Template.new(template) do |e, src, filters|
filters << Amrita2::Filters::GetTextFilter.new
end
t.text_domain = text_domain
bindtextdomain(t.text_domain)
#t.set_trace(STDOUT)
t.compiletime_binding = CompileTimeBinding
t
else
t = Amrita2::Template.new(template)
t.compiletime_binding = CompileTimeBinding
t
end
end
def render_amrita(template, local_assigns)
@@compiled_amrita2_templates[template] ||= setup_template(template)
tmpl = @@compiled_amrita2_templates[template]
b = setup_binding_of_view(local_assigns)
tmpl.render_with(b)
end
def setup_binding_of_view(local_assigns)
@action_view.instance_eval do
evaluate_assigns
b = binding
local_assigns.each do |k, v|
amrita_set_context_value(v)
eval "#{k}=amrita_get_context_value",b
end
b
end
end
end
module Helper
include ActionView::Helpers::UrlHelper
def view
@view ||= Thread::current[:amrita_rails_view]
end
def eval_in_view(&block)
view.instance_eval &block
end
def eval_in_view_without_escape(&block)
Amrita2::SanitizedString[eval_in_view(&block)]
end
end
end
=begin
class WithObject < Amrita2::Macro::Base
TemplateText = <<-'END'
<<%<
<% Thread::current[:amrita2_form_object] = $_[:name] || $_[:object] %>
<<_ :| Attr[:target_src=>:object]<
<<:contents>>
END
Option = {
:tag => "a:with_object",
:use_contents => :contents,
}
end
class Input < Amrita2::Macro::Base
TemplateText = <<-'END'
<<%<
<%
object = $_.delete(:object) || Thread::current[:amrita2_form_object]
input_id = $_.delete(:id)
other = $_.collect do |k, v|
"#{k}='#{v}'"
end
%>
target_filter="Attr[:value=><%= input_id.intern.inspect %>]"/>
END
Option = {
:tag => "a:input"
}
end
class TextField < Amrita2::Macro::Base
TemplateText = <<-'END'
<<%<
<%
object = $_.delete(:object) || Thread::current[:amrita2_form_object]
input_id = $_.delete(:id)
$_[:size] ||= 30
other = $_.collect do |k, v|
"#{k}='#{v}'"
end
%>
target_filter="Attr[:value=><%= input_id.intern.inspect %>]"/>
END
Option = {
:tag => "a:text_field",
}
end
class TextArea < Amrita2::Macro::Base
TemplateText = <<-'END'
<<%<
<%
object = $_.delete(:object) || Thread::current[:amrita2_form_object]
input_id = $_.delete(:id)
$_[:cols] ||= 40
$_[:rows] ||= 20
other = $_.collect do |k, v|
"#{k}='#{v}'"
end
%>