tanuki 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README.rdoc +19 -0
- data/app/tanuki/controller/controller.rb +3 -0
- data/app/tanuki/controller/default.thtml +5 -0
- data/app/tanuki/controller/index.thtml +1 -0
- data/app/tanuki/controller/link.thtml +7 -0
- data/app/tanuki/object/object.rb +3 -0
- data/app/tanuki/page/missing/default.thtml +2 -0
- data/app/tanuki/page/missing/missing.rb +9 -0
- data/app/user/page/index/default.thtml +121 -0
- data/app/user/page/index/index.rb +2 -0
- data/bin/tanuki +55 -0
- data/lib/tanuki/application.rb +111 -0
- data/lib/tanuki/argument/base.rb +27 -0
- data/lib/tanuki/argument/integer.rb +15 -0
- data/lib/tanuki/argument/integer_range.rb +22 -0
- data/lib/tanuki/argument/string.rb +15 -0
- data/lib/tanuki/argument.rb +41 -0
- data/lib/tanuki/configurator.rb +93 -0
- data/lib/tanuki/context.rb +36 -0
- data/lib/tanuki/controller_behavior.rb +324 -0
- data/lib/tanuki/i18n.rb +33 -0
- data/lib/tanuki/launcher.rb +20 -0
- data/lib/tanuki/loader.rb +131 -0
- data/lib/tanuki/module_extensions.rb +27 -0
- data/lib/tanuki/object_behavior.rb +32 -0
- data/lib/tanuki/template_compiler.rb +145 -0
- data/lib/tanuki/version.rb +6 -0
- data/lib/tanuki.rb +22 -0
- data/schema/tanuki/l10n/en/controller.yml +13 -0
- data/schema/tanuki/l10n/en/page.yml +31 -0
- data/schema/tanuki/l10n/ru/controller.yml +13 -0
- data/schema/tanuki/l10n/ru/page.yml +31 -0
- data/schema/tanuki/models/controller.yml +18 -0
- data/schema/tanuki/models/page.yml +48 -0
- metadata +168 -0
@@ -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
|
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
|
+
|