tanuki 0.1.3
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.
- 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
|
+
|