nagoro 2009.05

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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