nagoro 2009.05

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGELOG +446 -0
  2. data/MANIFEST +51 -0
  3. data/README.markdown +189 -0
  4. data/Rakefile +29 -0
  5. data/bin/nagoro +83 -0
  6. data/doc/COPYING +56 -0
  7. data/doc/GPL +340 -0
  8. data/doc/LEGAL +2 -0
  9. data/example/element/Html.nage +8 -0
  10. data/example/hello.nag +3 -0
  11. data/example/morpher.nag +23 -0
  12. data/lib/nagoro.rb +22 -0
  13. data/lib/nagoro/binding.rb +8 -0
  14. data/lib/nagoro/element.rb +46 -0
  15. data/lib/nagoro/pipe.rb +12 -0
  16. data/lib/nagoro/pipe/base.rb +56 -0
  17. data/lib/nagoro/pipe/compile.rb +30 -0
  18. data/lib/nagoro/pipe/element.rb +70 -0
  19. data/lib/nagoro/pipe/include.rb +36 -0
  20. data/lib/nagoro/pipe/instruction.rb +64 -0
  21. data/lib/nagoro/pipe/localization.rb +60 -0
  22. data/lib/nagoro/pipe/morph.rb +95 -0
  23. data/lib/nagoro/pipe/tidy.rb +49 -0
  24. data/lib/nagoro/scanner.rb +97 -0
  25. data/lib/nagoro/template.rb +89 -0
  26. data/lib/nagoro/tidy.rb +49 -0
  27. data/lib/nagoro/version.rb +3 -0
  28. data/nagoro.gemspec +28 -0
  29. data/spec/core_extensions.rb +33 -0
  30. data/spec/example/hello.rb +13 -0
  31. data/spec/helper.rb +19 -0
  32. data/spec/nagoro/listener/base.rb +19 -0
  33. data/spec/nagoro/pipe/compile.rb +31 -0
  34. data/spec/nagoro/pipe/element.rb +46 -0
  35. data/spec/nagoro/pipe/include.rb +17 -0
  36. data/spec/nagoro/pipe/instruction.rb +32 -0
  37. data/spec/nagoro/pipe/morph.rb +47 -0
  38. data/spec/nagoro/pipe/tidy.rb +23 -0
  39. data/spec/nagoro/template.rb +105 -0
  40. data/spec/nagoro/template/full.nag +26 -0
  41. data/spec/nagoro/template/hello.nag +1 -0
  42. data/tasks/bacon.rake +49 -0
  43. data/tasks/changelog.rake +18 -0
  44. data/tasks/gem.rake +22 -0
  45. data/tasks/gem_installer.rake +76 -0
  46. data/tasks/grancher.rake +12 -0
  47. data/tasks/install_dependencies.rake +6 -0
  48. data/tasks/manifest.rake +4 -0
  49. data/tasks/rcov.rake +19 -0
  50. data/tasks/release.rake +52 -0
  51. data/tasks/reversion.rake +8 -0
  52. metadata +105 -0
data/doc/LEGAL ADDED
@@ -0,0 +1,2 @@
1
+ This is a list of files included into nagoro but under different licenses.
2
+ Also included are files that are not under the copyright from Michael Fellinger.
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head>
3
+ <title>#@title</title>
4
+ </head>
5
+ <body>
6
+ #@content
7
+ </body>
8
+ </html>
data/example/hello.nag ADDED
@@ -0,0 +1,3 @@
1
+ <Html title="Hello, World!">
2
+ <h1>Hello, World!</h1>
3
+ </Html>
@@ -0,0 +1,23 @@
1
+ <html>
2
+ <head>
3
+ <title>Nagoro Pipe::Morph</title>
4
+ </head>
5
+ <body>
6
+ <?r list = [true, false, true] ?>
7
+
8
+ True items in list:
9
+ <div for="cond in list">
10
+ <h1 if="cond">#{cond}</h1>
11
+ </div>
12
+
13
+ False items in list:
14
+ <div for="cond in list">
15
+ <h1 unless="cond">#{cond}</h1>
16
+ </div>
17
+
18
+ Each item 3 times:
19
+ <div each="list">
20
+ <h1 times="3">#{_e}</h1>
21
+ </div>
22
+ </body>
23
+ </html>
data/lib/nagoro.rb ADDED
@@ -0,0 +1,22 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require 'nagoro/version'
4
+ require 'nagoro/template'
5
+
6
+ module Nagoro
7
+ autoload :Tidy, 'nagoro/tidy'
8
+
9
+ def self.compile(io, options = {})
10
+ Template.new.compile(io, options)
11
+ end
12
+
13
+ def self.render(obj, options = {})
14
+ compile(obj, options).result
15
+ end
16
+
17
+ def self.tidy_render(obj, options = {})
18
+ compile(obj, options).tidy_result
19
+ end
20
+
21
+ class Error < StandardError; end
22
+ end
@@ -0,0 +1,8 @@
1
+ module Nagoro
2
+ # BlankSlate or BasicObject inheritance needed
3
+ class BindingProvider
4
+ def self.binding
5
+ super
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,46 @@
1
+ module Nagoro
2
+ class Element
3
+ attr_accessor :content, :params
4
+
5
+ def initialize(content)
6
+ @content = content.strip
7
+ end
8
+
9
+ def render
10
+ @content
11
+ end
12
+
13
+ def params=(params = {})
14
+ params.each_pair do |key, value|
15
+ instance_variable_set("@#{key}", value)
16
+ end
17
+ end
18
+
19
+ def self.inherited(klass)
20
+ Nagoro::Pipe::Element::ELEMENTS[klass.to_s] = klass
21
+ end
22
+ end
23
+
24
+ # FileElement puts created elements into this module
25
+ module GeneratedElement
26
+ end
27
+
28
+ def self.FileElement(file)
29
+ element = Class.new(Element){
30
+ define_method(:element_file){
31
+ file
32
+ }
33
+
34
+ def render
35
+ main = File.read(element_file)
36
+ @delim = "T" << rand(8 << 100).to_s
37
+ eval(%{<<#@delim\n#{main}\n#@delim})
38
+ end
39
+ }
40
+ name = File.basename(file, File.extname(file))
41
+ GeneratedElement::const_set(name, element)
42
+ Pipe::Element::ELEMENTS.delete_if{|k,v| v == element}
43
+ Pipe::Element::ELEMENTS[name] = element
44
+ element
45
+ end
46
+ end
@@ -0,0 +1,12 @@
1
+ module Nagoro
2
+ module Pipe
3
+ autoload :Base, 'nagoro/pipe/base'
4
+ autoload :Compile, 'nagoro/pipe/compile'
5
+ autoload :Element, 'nagoro/pipe/element'
6
+ autoload :Include, 'nagoro/pipe/include'
7
+ autoload :Instruction, 'nagoro/pipe/instruction'
8
+ autoload :Localization, 'nagoro/pipe/localization'
9
+ autoload :Morph, 'nagoro/pipe/morph'
10
+ autoload :Tidy, 'nagoro/pipe/tidy'
11
+ end
12
+ end
@@ -0,0 +1,56 @@
1
+ module Nagoro
2
+ module Pipe
3
+ class Base
4
+ EMPTY_TAG = %w[ area base basefont br col frame hr
5
+ img input isindex link meta param ]
6
+
7
+ def initialize(io)
8
+ @body, @stack = [], []
9
+ @scanner = Scanner.new(io, self)
10
+ end
11
+
12
+ def result
13
+ @scanner.stream
14
+ @body.join
15
+ end
16
+
17
+ def tag_start(tag, original_attrs, value_attrs)
18
+ case tag
19
+ when *EMPTY_TAG
20
+ append "#{tag_with(tag, original_attrs)} />"
21
+ else
22
+ append "#{tag_with(tag, original_attrs)}>"
23
+ end
24
+ end
25
+
26
+ def tag_end(tag)
27
+ case tag
28
+ when *EMPTY_TAG
29
+ else
30
+ append "</#{tag}>"
31
+ end
32
+ end
33
+
34
+ def text(string)
35
+ append(string)
36
+ end
37
+
38
+ def append(string)
39
+ @body << string
40
+ end
41
+
42
+ def instruction(name, instruction)
43
+ append "<?#{name} #{instruction.to_s.strip} ?>"
44
+ end
45
+
46
+ def tag_with(tag, hash)
47
+ "<#{tag}#{hash.map{|k,v| %( #{k}=#{v}) }.join}"
48
+ end
49
+
50
+ def doctype(string)
51
+ string.strip!
52
+ append "<!DOCTYPE #{string}>"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,30 @@
1
+ module Nagoro
2
+ module Pipe
3
+ class Compile < Base
4
+ def instruction(name, instruction)
5
+ case name
6
+ when 'r'
7
+ append("`;#{instruction}; _out_ << %Q`")
8
+ when 'ro'
9
+ append("`;_out_ << (#{instruction}); _out_ << %Q`")
10
+ when 'h'
11
+ append("`;_out_ << h(#{instruction}); _out_ << %Q`")
12
+ when 'end'
13
+ append("`;end; _out_ << %Q`")
14
+ else
15
+ append("<?#{name} #{instruction.strip} ?>")
16
+ end
17
+ end
18
+
19
+ def result
20
+ "_out_ = []; _out_ << %Q`#{super}`; _out_.join"
21
+ end
22
+
23
+ def compile(template)
24
+ template = template.read if template.respond_to?(:read)
25
+ copy = template.gsub('`', '\\\\`')
26
+ compile!(copy)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,70 @@
1
+ module Nagoro
2
+ def self.element(name, obj = nil, &block)
3
+ Pipe::Element::ELEMENTS[name] = obj || block
4
+ end
5
+
6
+ def self.file_element(name, filename)
7
+ Pipe::Element::ELEMENTS[name] = FileElement(filename)
8
+ end
9
+
10
+ module Pipe
11
+ class Element < Base
12
+ ELEMENTS = {}
13
+
14
+ class ElementStruct < Struct.new(:tag, :attrs, :element, :content)
15
+ end
16
+
17
+ def tag_start(tag, original_attrs, value_attrs)
18
+ if element = ELEMENTS[tag]
19
+ @stack << ElementStruct.new(tag, value_attrs, element, [])
20
+ elsif tag =~ /^[A-Z]/
21
+ warn "Element: '<#{tag}>' not found."
22
+ super
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ def tag_end(tag)
29
+ estruct = @stack.reverse.find{|e| e.tag == tag}
30
+ if estruct and estruct.tag == tag
31
+ attrs, element, content = estruct.values_at(1..3)
32
+
33
+ @stack.pop
34
+
35
+ if element.respond_to?(:call)
36
+ append element.call(content.join, attrs)
37
+ else
38
+ instance = element.new(content.join)
39
+ instance.params = translate_attrs(instance, estruct.attrs)
40
+ append instance.render
41
+ end
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ def append(string)
48
+ if @stack.empty?
49
+ @body << string
50
+ else
51
+ @stack.last.content << string
52
+ end
53
+ end
54
+
55
+ def translate_attrs(instance, attrs)
56
+ hash = {}
57
+ attrs.each do |key, value|
58
+ case value
59
+ when /^@/
60
+ hash[key] = value
61
+ else
62
+ hash[key] = value
63
+ end
64
+ end
65
+
66
+ hash
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,36 @@
1
+ module Nagoro
2
+ module Pipe
3
+
4
+ # Include is used to include the contents of another file.
5
+ # The file will not be changed or interpreted in any way by this pipe.
6
+ #
7
+ # If the tag contains anything the contents will be put after the included
8
+ # contents.
9
+ #
10
+ # Syntax:
11
+ # <include href="some_file.xhtml" />
12
+ # <include src="some_file.xhtml" />
13
+
14
+ class Include < Base
15
+ def tag_start(tag, original_attrs, value_attrs)
16
+ if tag == 'include'
17
+ filename = value_attrs['href'] || value_attrs.fetch('src')
18
+ append contents(filename)
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def contents(file)
25
+ open(file){|o| o.read.strip }
26
+ rescue Errno::ENOENT, Errno::EISDIR => ex
27
+ warn ex.message
28
+ "<!-- #{ex} -->"
29
+ end
30
+
31
+ def tag_end(tag)
32
+ super unless tag == 'include'
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,64 @@
1
+ module Nagoro
2
+ module Pipe
3
+
4
+ # Instruction handles <??> instructions.
5
+ #
6
+ # It is based on a simple interpolation with String#% and one argument, the
7
+ # content of the instruction.
8
+ #
9
+ # If you want to add new instruction-formats, just add it to the
10
+ # Nagoro::Pipe::Instruction::INSTRUCTIONS Hash or use
11
+ # Nagoro::Pipe::Instruction::[] for convinience.
12
+ #
13
+ # The name of the instruction is matched with ===, so you can use regular
14
+ # expressions as keys as well.
15
+ #
16
+ # Syntax and results of available instructions:
17
+ # <?js alert('Hello, World!'); ?>
18
+ # # <script type="text/javascript"> alert('Hello, World!'); </script>
19
+ #
20
+ # <?js:src /js/jquery.js ?>
21
+ # # <script type="text/javascript" src="/js/jquery.js"></script>
22
+ #
23
+ # <?css body{ color: #f00; } ?>
24
+ # # <style type="text/css"> body{ color: #f00; } </style>
25
+ #
26
+ # <?css:src /css/coderay.css ?>
27
+ # # <style type="text/css" src="/css/coderay.css"></style>
28
+ #
29
+ # How to add new instructions:
30
+ # Nagoro::Pipe::Instruction['pre'] = '<pre>%s</pre>'
31
+ # Nagoro::Pipe::Instruction[/strip/] = '#{%(%s).strip}'
32
+
33
+ class Instruction < Base
34
+ INSTRUCTIONS = {
35
+ 'js' => '<script type="text/javascript"> %s </script>',
36
+ 'js:src' => '<script type="text/javascript" src="%s"></script>',
37
+ 'css' => '<style type="text/css"> %s </style>',
38
+ 'css:src' => '<style type="text/css" src="%s"></style>',
39
+ }
40
+
41
+ DEFAULT = "<?%s %s ?>"
42
+
43
+ def instruction(name, instruction)
44
+ instruction.to_s.strip!
45
+
46
+ if custom = INSTRUCTIONS[name]
47
+ @body << custom % instruction
48
+ else
49
+ @body << DEFAULT % [name, instruction]
50
+ end
51
+ end
52
+
53
+ class << self
54
+ def []=(key, value)
55
+ INSTRUCTIONS[key] = value
56
+ end
57
+
58
+ def [](key)
59
+ INSTRUCTIONS[key]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,60 @@
1
+ $KCODE = 'UTF-8'
2
+ require 'fileutils'
3
+ require 'yaml'
4
+ require 'ya2yaml'
5
+
6
+ module Nagoro
7
+ module Pipe
8
+ class Localization
9
+ attr_accessor :dict, :locale
10
+
11
+ CONFIG = {
12
+ :file => 'config/%s.yaml',
13
+ :locales => %w[ en ],
14
+ :default_language => 'en',
15
+ :mapping => {'en-us' => 'en', 'ja' => 'jp'},
16
+ :regex => /\[\[(.*?)\]\]/,
17
+ }
18
+
19
+ def self.[](conf = {})
20
+ CONFIG.merge!(conf)
21
+ end
22
+
23
+ def initialize
24
+ load_dictionary
25
+ end
26
+
27
+ def load_dictionary
28
+ file = CONFIG[:file]
29
+ files = CONFIG[:locales].map{|l| [l, file % l]}
30
+ existing, missing = files.partition{|(l,f)| File.file?(f)}
31
+ FileUtils.mkdir_p(File.dirname(file)) unless missing.empty?
32
+ missing.each{|(l,f)| FileUtils.touch(f)}
33
+
34
+ @dict = {}
35
+ files.each do |locale, file|
36
+ @dict[locale] = YAML.load_file(file) || {}
37
+ end
38
+ end
39
+
40
+ def call(template)
41
+ @template = template
42
+ @template.gsub!(CONFIG[:regex]) do |e|
43
+ localize($1)
44
+ end
45
+ end
46
+
47
+ def localize(string)
48
+ @dict[locale][string]
49
+ end
50
+
51
+ def to_html
52
+ @template
53
+ end
54
+
55
+ def reset
56
+ @template = ''
57
+ end
58
+ end
59
+ end
60
+ end