tanuki 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ module Tanuki
2
+
3
+ # Tanuki::TemplateCompiler is used for, well, compiling templates.
4
+ class TemplateCompiler
5
+
6
+ class << self
7
+
8
+ # Compiles a template from a given src string to ios for method sym in class klass.
9
+ def compile_template(ios, src, klass, sym)
10
+ ios << "# encoding: #{src.encoding}\nclass #{klass}\ndef #{sym}_view(*args,&block)\nproc do|_,ctx|\n" \
11
+ "if _has_tpl ctx,self.class,:#{sym}\nctx=_ctx(ctx)"
12
+ last_state = compile(ios, src)
13
+ ios << "\n_.call('',ctx)" unless PRINT_STATES.include? last_state
14
+ ios << "\nelse\n(_run_tpl ctx,self,:#{sym},*args,&block).call(_,ctx)\nend\nend\nend\nend"
15
+ end
16
+
17
+ # Compiles code from a given src string to ios.
18
+ def compile(ios, src)
19
+ state = :outer
20
+ last_state = nil
21
+ index = 0
22
+ trim_newline = false
23
+ code_buf = ''
24
+ begin
25
+ if new_index = src[index..-1].index(pattern = expect_pattern(state))
26
+ new_index += index
27
+ match = src[index..-1].match(pattern)[0]
28
+ new_state = next_state(state, match)
29
+ else
30
+ new_state = nil
31
+ end
32
+ if state == :outer
33
+ s = new_index ? src[index, new_index - index] : src[index..-1]
34
+ if trim_newline && !s.empty?
35
+ s[0] = '' if s[0] == "\n"
36
+ trim_newline = false
37
+ end
38
+ if new_state == :code_skip
39
+ code_buf << s.dup << match[0..-2]
40
+ index = new_index + match.length
41
+ next
42
+ elsif not s.empty?
43
+ ios << "\n_.call(#{(code_buf << s).inspect},ctx)"
44
+ code_buf = ''
45
+ end
46
+ end
47
+ if new_index
48
+ unless state != :outer && new_state == :code_skip
49
+ if new_state == :outer
50
+ process_code_state(ios, code_buf << src[index...new_index], state)
51
+ code_buf = ''
52
+ end
53
+ index = new_index + match.length
54
+ trim_newline = true if (match == '-%>')
55
+ last_state = state unless state == :code_comment
56
+ state = new_state
57
+ else
58
+ code_buf << src[index...new_index] << '%>'
59
+ index = new_index + match.length
60
+ end
61
+ end
62
+ end until new_index.nil?
63
+ last_state
64
+ end
65
+
66
+ private
67
+
68
+ # Scanner states that output the evaluated result.
69
+ PRINT_STATES = [:outer, :code_print]
70
+
71
+ def process_code_state(ios, src, state)
72
+ src.strip!
73
+ src.gsub! /^[ \t]+/, ''
74
+ case state
75
+ when :code_line, :code_span then
76
+ ios << "\n#{src}"
77
+ when :code_print then
78
+ ios << "\n_.call((#{src}),ctx)"
79
+ when :code_template then
80
+ ios << "\n(#{src}).call(_,ctx)"
81
+ when :code_visitor
82
+ inner_m = src.match /^([^ \(]+)?(\([^\)]*\))?\s*(.*)$/
83
+ ios << "\n#{inner_m[1]}_result=(#{inner_m[3]}).call(#{inner_m[1]}_visitor#{inner_m[2]},ctx)"
84
+ when :l10n then
85
+ localize(ios, src)
86
+ end
87
+ end
88
+
89
+ # Returns the next expected pattern for a given state.
90
+ def expect_pattern(state)
91
+ case state
92
+ when :outer then %r{^\s*%%?|<%[=!_#%]?|<l10n>}
93
+ when :code_line then %r{\n|\Z}
94
+ when :code_span, :code_print, :code_template, :code_visitor, :code_comment then %r{[-%]?%>}
95
+ when :l10n then %r{<\/l10n>}
96
+ end
97
+ end
98
+
99
+ # Returns the next state for a given match and current state.
100
+ def next_state(state, match)
101
+ case state
102
+ when :outer then
103
+ case match
104
+ when /\A\s*%\Z/ then :code_line
105
+ when /\A\s*%%\Z/ then :code_skip
106
+ when '<%' then :code_span
107
+ when '<%=' then :code_print
108
+ when '<%!' then :code_template
109
+ when '<%_' then :code_visitor
110
+ when '<%#' then :code_comment
111
+ when '<%%' then :code_skip
112
+ when '<l10n>' then :l10n
113
+ end
114
+ when :code_line then :outer
115
+ when :code_span, :code_print, :code_template, :code_visitor, :code_comment then
116
+ case match
117
+ when '%%>' then :code_skip
118
+ else :outer
119
+ end
120
+ when :l10n then :outer
121
+ end
122
+ end
123
+
124
+ # Generates localization code from src.
125
+ def localize(ios, src)
126
+ index = 0
127
+ lngs = []
128
+ ios << "\ncase ctx.best_language "
129
+ code = StringIO.new
130
+ while index = src.index(/<[a-z]{2}>/, index)
131
+ lngs << (lng = src[index + 1, 2].to_sym)
132
+ if end_index = src.index(/<\/#{lng}>/, index += 4)
133
+ code << "\nwhen #{lng.inspect} then"
134
+ compile(code, src[index...end_index])
135
+ index = end_index + 5
136
+ end
137
+ end
138
+ ios << "#{lngs.inspect.gsub(/ /, '')}#{code.string}\nend"
139
+ end
140
+
141
+ end # end class << self
142
+
143
+ end # end TemplateCompiler
144
+
145
+ end # end Tanuki
@@ -0,0 +1,6 @@
1
+ module Tanuki
2
+
3
+ # Tanuki framework version.
4
+ VERSION = '0.1.3'
5
+
6
+ end # end Tanuki
data/lib/tanuki.rb ADDED
@@ -0,0 +1,22 @@
1
+ module Tanuki
2
+ libdir = File.dirname(__FILE__)
3
+ $:.unshift(libdir) unless $:.include?(libdir)
4
+ end
5
+
6
+ require 'rack'
7
+ require 'fileutils'
8
+ require 'yaml'
9
+ require 'escape_utils'
10
+ require 'escape_utils/url/rack'
11
+ require 'tanuki/version'
12
+ require 'tanuki/module_extensions'
13
+ require 'tanuki/argument'
14
+ require 'tanuki/configurator'
15
+ require 'tanuki/context'
16
+ require 'tanuki/controller_behavior'
17
+ require 'tanuki/launcher'
18
+ require 'tanuki/loader'
19
+ require 'tanuki/i18n'
20
+ require 'tanuki/object_behavior'
21
+ require 'tanuki/template_compiler'
22
+ require 'tanuki/application'
@@ -0,0 +1,13 @@
1
+ ---
2
+ numeral: [controller, controllers]
3
+ plural: controllers
4
+ attributes:
5
+ class:
6
+ title: class
7
+ description: Controller class name
8
+ title:
9
+ title: title
10
+ description: Readable controller title
11
+ pages:
12
+ title: pages
13
+ description: Pages with this controller
@@ -0,0 +1,31 @@
1
+ ---
2
+ numeral: [page, pages]
3
+ plural: pages
4
+ attributes:
5
+ parent:
6
+ title: parent
7
+ description: Parent page
8
+ children:
9
+ title: children
10
+ description: Child pages
11
+ title:
12
+ title: title
13
+ description: Short page title
14
+ long_title:
15
+ title: long title
16
+ description: Long page title
17
+ content:
18
+ title: content
19
+ description: Page content
20
+ controller:
21
+ title: controller
22
+ description: Page creation logic
23
+ default_route:
24
+ title: default route
25
+ description: Path to main child page
26
+ use_default_route:
27
+ title: use default route
28
+ description: Use path to main child page
29
+ hidden:
30
+ title: hidden
31
+ description: Page is hidden or not
@@ -0,0 +1,13 @@
1
+ ---
2
+ numeral: [контроллер, контроллера, контроллеров]
3
+ plural: контроллеры
4
+ attributes:
5
+ class:
6
+ title: класс
7
+ description: Имя класса контроллера
8
+ title:
9
+ title: название
10
+ description: Читабельное название контроллера
11
+ pages:
12
+ title: страницы
13
+ description: Страницы, управляемые данным контроллером
@@ -0,0 +1,31 @@
1
+ ---
2
+ numeral: [страница, страницы, страниц]
3
+ plural: страницы
4
+ attributes:
5
+ parent:
6
+ title: родитель
7
+ description: Родительская страница
8
+ children:
9
+ title: дети
10
+ description: Дочерние страницы
11
+ title:
12
+ title: заголовок
13
+ description: Краткий заголовок страницы
14
+ long_title:
15
+ title: детальный заголовок
16
+ description: Детальный заголовок страницы
17
+ content:
18
+ title: содержимое
19
+ description: Содержимое страницы
20
+ controller:
21
+ title: контроллер
22
+ description: Программа, формирующая страницу
23
+ default_route:
24
+ title: переход
25
+ description: Путь к главной дочерней странице
26
+ use_default_route:
27
+ title: использовать переход
28
+ description: Переходить к главной дочерней странице
29
+ hidden:
30
+ title: скрыта
31
+ description: Скрыта страница или нет
@@ -0,0 +1,18 @@
1
+ ---
2
+ namespaces:
3
+ default: Tanuki
4
+ source:
5
+ table: tanuki_controllers
6
+ alias: tc
7
+ key: tc.class
8
+ to_s: tc.title
9
+ attributes:
10
+ class: { type: String, size: 80, required: true }
11
+ title: { type: String, required: true }
12
+ pages: { type: Collection }
13
+ l10n:
14
+ adapter: Shadow
15
+ table: tanuki_controllers_l10n
16
+ list:
17
+ class: { link: true }
18
+ title: ~
@@ -0,0 +1,48 @@
1
+ ---
2
+ namespaces:
3
+ default: Tanuki
4
+ source:
5
+ table: tanuki_pages
6
+ alias: tp
7
+ key: tp.id
8
+ to_s: [tp.long_title, tp.title]
9
+ order:
10
+ by:
11
+ tp.parent_id: asc
12
+ tp.order: asc
13
+ reorder: tp.order
14
+ attributes:
15
+ parent: { type: Object, required: true }
16
+ children: { type: Collection }
17
+ title: { type: String, size: 45, required: true }
18
+ long_title: { type: String, default: ~ }
19
+ content: { type: Html, required: true }
20
+ controller: { type: Object, required: true }
21
+ route: { type: String, size: 45, required: true, default: '' }
22
+ default_route: { type: String, size: 45, required: true, default: '' }
23
+ use_default_route: { type: Boolean, default: false }
24
+ hidden: { type: Boolean, default: false }
25
+ relations:
26
+ parent:
27
+ class: Page
28
+ type: one-to-many
29
+ inverse: children
30
+ join:
31
+ alias: tpp
32
+ on:
33
+ tpp.id: tp.parent_id
34
+ controller:
35
+ class: Controller
36
+ type: one-to-many
37
+ inverse: pages
38
+ join:
39
+ alias: tc
40
+ on:
41
+ tc.id: tp.parent_id
42
+ list:
43
+ parent: ~
44
+ title: { link: true }
45
+ controller: ~
46
+ default_route: ~
47
+ use_default_route: ~
48
+ hidden: ~
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tanuki
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 3
10
+ version: 0.1.3
11
+ platform: ruby
12
+ authors:
13
+ - Anatoly Ressin
14
+ - Dimitry Solovyov
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-08-19 00:00:00 +03:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rack
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 15
31
+ segments:
32
+ - 1
33
+ - 0
34
+ version: "1.0"
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: escape_utils
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 17
46
+ segments:
47
+ - 0
48
+ - 1
49
+ - 5
50
+ version: 0.1.5
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rake
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 49
62
+ segments:
63
+ - 0
64
+ - 8
65
+ - 7
66
+ version: 0.8.7
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 27
78
+ segments:
79
+ - 1
80
+ - 3
81
+ - 0
82
+ version: 1.3.0
83
+ type: :development
84
+ version_requirements: *id004
85
+ description: Tanuki is an MVVM-inspired web framework that fancies idiomatic Ruby, DRY and extensibility by its design.
86
+ email: tanuki@dimituri.com
87
+ executables:
88
+ - tanuki
89
+ extensions: []
90
+
91
+ extra_rdoc_files: []
92
+
93
+ files:
94
+ - app/tanuki/controller/controller.rb
95
+ - app/tanuki/controller/default.thtml
96
+ - app/tanuki/controller/index.thtml
97
+ - app/tanuki/controller/link.thtml
98
+ - app/tanuki/object/object.rb
99
+ - app/tanuki/page/missing/default.thtml
100
+ - app/tanuki/page/missing/missing.rb
101
+ - app/user/page/index/default.thtml
102
+ - app/user/page/index/index.rb
103
+ - bin/tanuki
104
+ - lib/tanuki/application.rb
105
+ - lib/tanuki/argument/base.rb
106
+ - lib/tanuki/argument/integer.rb
107
+ - lib/tanuki/argument/integer_range.rb
108
+ - lib/tanuki/argument/string.rb
109
+ - lib/tanuki/argument.rb
110
+ - lib/tanuki/configurator.rb
111
+ - lib/tanuki/context.rb
112
+ - lib/tanuki/controller_behavior.rb
113
+ - lib/tanuki/i18n.rb
114
+ - lib/tanuki/launcher.rb
115
+ - lib/tanuki/loader.rb
116
+ - lib/tanuki/module_extensions.rb
117
+ - lib/tanuki/object_behavior.rb
118
+ - lib/tanuki/template_compiler.rb
119
+ - lib/tanuki/version.rb
120
+ - lib/tanuki.rb
121
+ - schema/tanuki/l10n/en/controller.yml
122
+ - schema/tanuki/l10n/en/page.yml
123
+ - schema/tanuki/l10n/ru/controller.yml
124
+ - schema/tanuki/l10n/ru/page.yml
125
+ - schema/tanuki/models/controller.yml
126
+ - schema/tanuki/models/page.yml
127
+ - LICENSE
128
+ - README.rdoc
129
+ has_rdoc: true
130
+ homepage: http://github.com/dimituri/tanuki
131
+ licenses: []
132
+
133
+ post_install_message:
134
+ rdoc_options: []
135
+
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 49
144
+ segments:
145
+ - 1
146
+ - 9
147
+ - 1
148
+ version: 1.9.1
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ hash: 23
155
+ segments:
156
+ - 1
157
+ - 3
158
+ - 6
159
+ version: 1.3.6
160
+ requirements: []
161
+
162
+ rubyforge_project:
163
+ rubygems_version: 1.3.7
164
+ signing_key:
165
+ specification_version: 3
166
+ summary: Web framework with balls!
167
+ test_files: []
168
+