tanuki 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.rdoc +10 -2
- data/app/tanuki/attribute/attribute.rb +2 -2
- data/app/tanuki/base/base.rb +2 -2
- data/app/tanuki/controller/controller.rb +2 -2
- data/app/tanuki/controller/default.thtml +1 -1
- data/app/tanuki/controller/index.thtml +1 -1
- data/app/tanuki/controller/link.thtml +1 -1
- data/app/tanuki/manager/controller/controller.rb +2 -0
- data/app/tanuki/manager/page/page.rb +2 -0
- data/app/tanuki/meta_model/manager.ttxt +1 -1
- data/app/tanuki/meta_model/manager_base.ttxt +2 -2
- data/app/tanuki/meta_model/meta_model.rb +2 -2
- data/app/tanuki/meta_model/model.ttxt +1 -1
- data/app/tanuki/meta_model/model_base.ttxt +2 -2
- data/app/tanuki/model/controller/controller.rb +2 -0
- data/app/tanuki/model/model.rb +2 -2
- data/app/tanuki/model/page/page.rb +2 -0
- data/app/tanuki/page/missing/default.thtml +1 -1
- data/app/tanuki/page/missing/missing.rb +2 -2
- data/app/user/page/index/default.thtml +1 -1
- data/app/user/page/index/index.rb +2 -2
- data/bin/tanuki +3 -201
- data/config/common.rb +1 -1
- data/config/common_application.rb +3 -3
- data/config/development_application.rb +1 -1
- data/config/production_application.rb +1 -1
- data/config/test_application.rb +2 -0
- data/lib/tanuki/application.rb +27 -7
- data/lib/tanuki/argument/base.rb +3 -3
- data/lib/tanuki/argument/integer.rb +3 -3
- data/lib/tanuki/argument/integer_range.rb +3 -3
- data/lib/tanuki/argument/string.rb +3 -3
- data/lib/tanuki/argument.rb +3 -3
- data/lib/tanuki/behavior/controller_behavior.rb +40 -8
- data/lib/tanuki/behavior/meta_model_behavior.rb +62 -20
- data/lib/tanuki/behavior/model_behavior.rb +4 -4
- data/lib/tanuki/behavior/object_behavior.rb +2 -2
- data/lib/tanuki/configurator.rb +2 -2
- data/lib/tanuki/context.rb +8 -3
- data/lib/tanuki/extensions/module.rb +16 -1
- data/lib/tanuki/extensions/rack/builder.rb +2 -2
- data/lib/tanuki/extensions/rack/server.rb +2 -2
- data/lib/tanuki/extensions/rack/static_dir.rb +2 -2
- data/lib/tanuki/i18n.rb +2 -2
- data/lib/tanuki/launcher.rb +2 -2
- data/lib/tanuki/loader.rb +24 -4
- data/lib/tanuki/model_generator.rb +114 -0
- data/lib/tanuki/template_compiler.rb +89 -13
- data/lib/tanuki/utility/create.rb +38 -0
- data/lib/tanuki/utility/generate.rb +52 -0
- data/lib/tanuki/utility/help.rb +16 -0
- data/lib/tanuki/utility/server.rb +23 -0
- data/lib/tanuki/utility/version.rb +15 -0
- data/lib/tanuki/utility.rb +65 -0
- data/lib/tanuki/version.rb +2 -2
- data/lib/tanuki.rb +1 -2
- data/schema/tanuki/l10n/en/controller.yml +1 -1
- data/schema/tanuki/l10n/en/page.yml +1 -1
- data/schema/tanuki/l10n/ru/controller.yml +1 -1
- data/schema/tanuki/l10n/ru/page.yml +1 -1
- data/schema/tanuki/models/controller.yml +1 -1
- data/schema/tanuki/models/page.yml +1 -1
- metadata +16 -5
- data/lib/tanuki/extensions/object.rb +0 -12
data/LICENSE
CHANGED
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
16
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
THE SOFTWARE.
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -17,6 +17,14 @@ Fire up the terminal and type:
|
|
17
17
|
|
18
18
|
View the result at: http://localhost:3000
|
19
19
|
|
20
|
-
==
|
20
|
+
== Hack on the Core
|
21
21
|
|
22
|
-
{
|
22
|
+
If you would like to study the framework and contribute, try making sense of the project {wiki}[https://github.com/assistunion/tanuki/wiki], then move on to {documentation}[http://rubydoc.info/github/assistunion/tanuki].
|
23
|
+
|
24
|
+
== Acknowledgements
|
25
|
+
|
26
|
+
Tanuki is thankful to:
|
27
|
+
|
28
|
+
* All of the core contributors
|
29
|
+
* Erika Olehno, for the cute logo
|
30
|
+
* {Rack}[http://rack.rubyforge.org/], {Sequel}[http://sequel.rubyforge.org/], {escape_utils}[https://github.com/brianmario/escape_utils], and {Active Support}[https://github.com/rails/rails/tree/master/activesupport] authors and contributors, for their amazing work
|
data/app/tanuki/base/base.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
class
|
1
|
+
class Tanuki::Base
|
2
2
|
include Tanuki::BaseBehavior
|
3
|
-
end
|
3
|
+
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
class
|
1
|
+
class Tanuki::Controller < Tanuki::Base
|
2
2
|
include Tanuki::ControllerBehavior
|
3
|
-
end
|
3
|
+
end
|
@@ -1 +1 @@
|
|
1
|
-
<%= self.class %> is under construction
|
1
|
+
<%= self.class %> is under construction
|
@@ -1,2 +1,2 @@
|
|
1
1
|
class <%= class_name_for :manager %>
|
2
|
-
end
|
2
|
+
end
|
@@ -1,2 +1,2 @@
|
|
1
|
-
class <%= class_name_for :manager_base %> <
|
2
|
-
end
|
1
|
+
class <%= class_name_for :manager_base %> < Tanuki::Controller
|
2
|
+
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
class
|
1
|
+
class Tanuki::MetaModel < Tanuki::Base
|
2
2
|
include Tanuki::MetaModelBehavior
|
3
|
-
end
|
3
|
+
end
|
@@ -1,2 +1,2 @@
|
|
1
1
|
class <%= class_name_for :model %>
|
2
|
-
end
|
2
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class <%= class_name_for :model_base %> <
|
1
|
+
class <%= class_name_for :model_base %> < Tanuki::Base
|
2
2
|
extend Tanuki::ModelBehavior
|
3
3
|
|
4
4
|
class << self
|
@@ -9,4 +9,4 @@ class <%= class_name_for :model_base %> < Tanuki_Base
|
|
9
9
|
def get(ctx, *args)
|
10
10
|
end
|
11
11
|
end
|
12
|
-
end
|
12
|
+
end
|
data/app/tanuki/model/model.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
class
|
1
|
+
class Tanuki::Model
|
2
2
|
include Tanuki::ModelBehavior
|
3
|
-
end
|
3
|
+
end
|
@@ -1,2 +1,2 @@
|
|
1
|
-
class
|
2
|
-
end
|
1
|
+
class User::Page::Index < Tanuki::Controller
|
2
|
+
end
|
data/bin/tanuki
CHANGED
@@ -1,202 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
class << self
|
7
|
-
|
8
|
-
def create(name)
|
9
|
-
unless name
|
10
|
-
puts "To use this command: `create <name>'"
|
11
|
-
return
|
12
|
-
end
|
13
|
-
require 'fileutils'
|
14
|
-
project_dir = File.expand_path(name)
|
15
|
-
if File.exists? project_dir
|
16
|
-
puts "File or directory `#{name}' already exists!"
|
17
|
-
return
|
18
|
-
end
|
19
|
-
version unless @in_repl
|
20
|
-
puts "\n creating #{name = name.downcase}"
|
21
|
-
FileUtils.mkdir project_dir
|
22
|
-
file_source = File.expand_path(File.join('..', '..'), __FILE__)
|
23
|
-
puts " creating #{File.join(name, 'app')}"
|
24
|
-
FileUtils.mkdir_p File.join(project_dir, 'app', 'user')
|
25
|
-
FileUtils.cp_r File.join(file_source, 'app', 'user'), File.join(project_dir, 'app')
|
26
|
-
puts " creating #{File.join(name, 'gen')}"
|
27
|
-
FileUtils.mkdir(gen_dir = File.join(project_dir, 'gen'))
|
28
|
-
FileUtils.chmod(0777, gen_dir)
|
29
|
-
puts " creating #{File.join(name, 'public')}"
|
30
|
-
FileUtils.mkdir(File.join(project_dir, 'public'))
|
31
|
-
puts " creating #{File.join(name, 'schema')}"
|
32
|
-
FileUtils.mkdir(File.join(project_dir, 'schema'))
|
33
|
-
Dir.chdir(project_dir) if @in_repl
|
34
|
-
end
|
35
|
-
|
36
|
-
def generate(cwd)
|
37
|
-
version unless @in_repl
|
38
|
-
cwd = cwd ? File.expand_path(cwd) : Dir.pwd
|
39
|
-
puts "Working directory is: #{cwd}\nTo specify another: `generate <path>'"
|
40
|
-
require 'active_support/inflector'
|
41
|
-
require 'yaml'
|
42
|
-
require 'fileutils'
|
43
|
-
require 'tanuki/extensions/object'
|
44
|
-
require 'tanuki/behavior/meta_model_behavior'
|
45
|
-
require 'tanuki/behavior/model_behavior'
|
46
|
-
require 'tanuki/behavior/object_behavior'
|
47
|
-
require 'tanuki/configurator'
|
48
|
-
require 'tanuki/context'
|
49
|
-
require 'tanuki/loader'
|
50
|
-
require 'tanuki/template_compiler'
|
51
|
-
Loader.context = ctx = Context
|
52
|
-
default_root = File.expand_path(File.join('..', '..'), __FILE__)
|
53
|
-
cfg = Configurator.new(Context, cwd)
|
54
|
-
if cwd != default_root
|
55
|
-
cfg.config_root = File.join(default_root, 'config')
|
56
|
-
cfg.load_config :common
|
57
|
-
end
|
58
|
-
cfg.config_root = File.join(cwd, 'config')
|
59
|
-
cfg.load_config :common, cwd != default_root
|
60
|
-
puts "\n looking for models"
|
61
|
-
@tried = {}
|
62
|
-
@models = {}
|
63
|
-
local_schema_root = File.expand_path(File.join('..', '..', 'schema'), __FILE__)
|
64
|
-
generate_in(ctx.schema_root, ctx)
|
65
|
-
generate_in(local_schema_root, ctx) if ctx.schema_root != local_schema_root
|
66
|
-
@tried.each_pair do |name, arys|
|
67
|
-
puts "\n found: #{name}"
|
68
|
-
arys.each_pair {|ary_name, ary| puts %{ #{ary_name}:\n - #{ary.join "\n - "}} unless ary.empty? }
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def generate_in(schema_root, ctx)
|
73
|
-
Dir.entries(schema_root)[2..-1].each do |namespace_path|
|
74
|
-
namespace_name = namespace_path.split('_').map {|s| s.capitalize }.join
|
75
|
-
namespace = @models[namespace_name] = {}
|
76
|
-
Dir.glob(File.join(schema_root, namespace_path, 'models', '*.yml')) do |file_path|
|
77
|
-
model_name = File.basename(file_path, '.yml').split('_').map {|s| s.capitalize }.join
|
78
|
-
meta_model = namespace[model_name] = Tanuki_MetaModel.new(
|
79
|
-
namespace_name,
|
80
|
-
model_name,
|
81
|
-
YAML.load_file(file_path),
|
82
|
-
@models
|
83
|
-
)
|
84
|
-
meta_model.process!
|
85
|
-
if @tried.include? namespace_model_name = "#{namespace_name}.#{model_name}"
|
86
|
-
next
|
87
|
-
else
|
88
|
-
@tried[namespace_model_name] = {:generated => [], :failed => [], :skipped => []}
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
@models.each do |namespace_name, namespace |
|
94
|
-
namespace.each do |model_name, meta_model|
|
95
|
-
meta_model.process_relations!
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
@models.each do |namespace_name, namespace |
|
100
|
-
namespace.each do |model_name, meta_model|
|
101
|
-
namespace_model_name = "#{namespace_name}.#{model_name}"
|
102
|
-
{
|
103
|
-
:model => false,
|
104
|
-
:model_base => true,
|
105
|
-
:manager => false,
|
106
|
-
:manager_base => true
|
107
|
-
}.each do |class_type, base|
|
108
|
-
class_name = meta_model.class_name_for class_type
|
109
|
-
path = Tanuki::Loader.class_path(class_name, base ? ctx.gen_root : ctx.app_root)
|
110
|
-
if base || !(File.exists? path)
|
111
|
-
begin
|
112
|
-
dirname = File.dirname(path)
|
113
|
-
FileUtils.mkdir_p dirname unless File.directory? dirname
|
114
|
-
File.open path, 'w' do |file|
|
115
|
-
writer = proc {|out| file.print out.to_s }
|
116
|
-
Loader.run_template({}, meta_model, class_type).call(writer, ctx)
|
117
|
-
end
|
118
|
-
@tried[namespace_model_name][:generated] << class_name unless base
|
119
|
-
rescue
|
120
|
-
@tried[namespace_model_name][:failed] << class_name unless base
|
121
|
-
end
|
122
|
-
else
|
123
|
-
@tried[namespace_model_name][:skipped] << class_name unless base
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def execute(args)
|
131
|
-
case args[0]
|
132
|
-
when 'create' then create(args[1])
|
133
|
-
when 'exit' then @in_repl ? (puts 'Bye bye!'; return false) : help
|
134
|
-
when 'generate' then generate(args[1])
|
135
|
-
when 'help' then help
|
136
|
-
when 'server' then return server(args[1])
|
137
|
-
when 'version' then version
|
138
|
-
when nil then start_repl unless @in_repl
|
139
|
-
else help
|
140
|
-
end
|
141
|
-
true
|
142
|
-
end
|
143
|
-
|
144
|
-
def help
|
145
|
-
version unless @in_repl
|
146
|
-
puts "\nbasic commands:\n"
|
147
|
-
commands = {}
|
148
|
-
commands['create'] = 'create a new app with the given name'
|
149
|
-
commands['exit'] = 'exit this utility' if @in_repl
|
150
|
-
commands['generate'] = 'generate models for application schema'
|
151
|
-
commands['help'] = 'show help (this text)'
|
152
|
-
commands['server'] = 'run application'
|
153
|
-
commands['version'] = 'show framework version'
|
154
|
-
commands.each_pair {|k, v| puts ' %-8s %s' % [k, v] }
|
155
|
-
end
|
156
|
-
|
157
|
-
def init
|
158
|
-
@in_repl = false
|
159
|
-
execute ARGV
|
160
|
-
end
|
161
|
-
|
162
|
-
def server(env=nil)
|
163
|
-
env = env ? env.to_sym : :development
|
164
|
-
puts %{Calling for a Tanuki in "#{Dir.pwd}"}
|
165
|
-
version unless @in_repl
|
166
|
-
require 'tanuki'
|
167
|
-
begin
|
168
|
-
Application.run
|
169
|
-
false
|
170
|
-
rescue Interrupt
|
171
|
-
puts 'Tanuki ran away!'
|
172
|
-
false
|
173
|
-
rescue SystemCallError
|
174
|
-
puts 'Tanuki ran away! Someone else is playing here.'
|
175
|
-
true
|
176
|
-
end if Application.configure(env)
|
177
|
-
end
|
178
|
-
|
179
|
-
def start_repl
|
180
|
-
@in_repl = true
|
181
|
-
version
|
182
|
-
print 'tanuki>'
|
183
|
-
print "\ntanuki>" while gets && execute($_.chomp.scan /(?<=")\w[\w\s]*(?=")|\w+/)
|
184
|
-
end
|
185
|
-
|
186
|
-
def version
|
187
|
-
begin
|
188
|
-
require 'tanuki/version'
|
189
|
-
rescue LoadError
|
190
|
-
$:.unshift File.expand_path(File.join('..', '..', 'lib'), __FILE__)
|
191
|
-
require 'tanuki/version'
|
192
|
-
end
|
193
|
-
puts "Tanuki version #{VERSION}"
|
194
|
-
end
|
195
|
-
|
196
|
-
end # end class << self
|
197
|
-
|
198
|
-
end # end Utility
|
199
|
-
|
200
|
-
end # end Tanuki
|
201
|
-
|
202
|
-
Tanuki::Utility.init if File.basename(__FILE__) == File.basename($0)
|
2
|
+
$:.unshift File.expand_path(File.join('..', '..', 'lib'), __FILE__)
|
3
|
+
require 'tanuki/utility'
|
4
|
+
Tanuki::Utility.init if File.basename(__FILE__) == File.basename($0)
|
data/config/common.rb
CHANGED
@@ -11,8 +11,8 @@ set :port, 3000
|
|
11
11
|
set :development, false
|
12
12
|
|
13
13
|
# Default controllers
|
14
|
-
set :root_page, ::
|
15
|
-
set :missing_page, ::
|
14
|
+
set :root_page, ::User::Page::Index
|
15
|
+
set :missing_page, ::Tanuki::Page::Missing
|
16
16
|
|
17
17
|
# Internationalization
|
18
18
|
set :i18n, false
|
@@ -30,4 +30,4 @@ visitor :string do s = ''; proc {|out| s << out.to_s } end
|
|
30
30
|
argument Fixnum, Argument::Integer
|
31
31
|
argument Bignum, Argument::Integer
|
32
32
|
argument Range, Argument::IntegerRange
|
33
|
-
argument String, Argument::String
|
33
|
+
argument String, Argument::String
|
@@ -1,2 +1,2 @@
|
|
1
1
|
load_config :common_application
|
2
|
-
set :development, false
|
2
|
+
set :development, false
|
data/lib/tanuki/application.rb
CHANGED
@@ -17,12 +17,17 @@ module Tanuki
|
|
17
17
|
begin
|
18
18
|
default_root = File.expand_path(File.join('..', '..', '..'), __FILE__)
|
19
19
|
@cfg = Configurator.new(Context, pwd = Dir.pwd)
|
20
|
+
|
21
|
+
# Configure in default root (e.g. gem root)
|
20
22
|
if pwd != default_root
|
21
23
|
@cfg.config_root = File.join(default_root, 'config')
|
22
24
|
@cfg.load_config(([:development, :production].include? env) ? :"#{env}_application" : :common_application)
|
23
25
|
end
|
26
|
+
|
27
|
+
# Configure in application root
|
24
28
|
@cfg.config_root = File.join(pwd, 'config')
|
25
29
|
@cfg.load_config :"#{env}_application", pwd != default_root
|
30
|
+
|
26
31
|
return true
|
27
32
|
rescue NameError => e
|
28
33
|
if e.name =~ /\AA-Z/
|
@@ -54,10 +59,14 @@ module Tanuki
|
|
54
59
|
def run
|
55
60
|
configure_middleware(rack_builder = Rack::Builder.new)
|
56
61
|
rack_builder.run(rack_app)
|
62
|
+
|
63
|
+
# Choose and start a Rack handler
|
57
64
|
@context.running_server = available_server
|
58
|
-
|
59
|
-
|
60
|
-
|
65
|
+
@context.running_server.run rack_builder.to_app, :Host => @context.host, :Port => @context.port do |server|
|
66
|
+
[:INT, :TERM].each {|sig| trap(sig) { (server.respond_to? :stop!) ? server.stop! : server.stop } }
|
67
|
+
puts "A#{'n' if @environment =~ /\A[aeiou]/} #{@environment} Tanuki appears! Press Ctrl-C to set it free.",
|
68
|
+
"You used #{@context.running_server.name.gsub(/.*::/, '')} at #{@context.host}:#{@context.port}."
|
69
|
+
end
|
61
70
|
end
|
62
71
|
|
63
72
|
# Adds a given +middleware+ with optional +args+ and +block+ to the Rack middleware pipeline.
|
@@ -115,14 +124,23 @@ module Tanuki
|
|
115
124
|
proc do |env|
|
116
125
|
request_ctx = ctx.child
|
117
126
|
request_ctx.templates = {}
|
127
|
+
|
128
|
+
# If there are trailing slashes in path, don't dispatch
|
118
129
|
if match = env['PATH_INFO'].match(/^(.+)(?<!\$)\/$/)
|
130
|
+
|
131
|
+
# Remove trailing slash in the path and redirect
|
119
132
|
loc = match[1]
|
120
133
|
loc << "?#{env['QUERY_STRING']}" unless env['QUERY_STRING'].empty?
|
121
134
|
[301, {'Location' => loc, 'Content-Type' => 'text/html; charset=utf-8'}, []]
|
135
|
+
|
122
136
|
else
|
137
|
+
|
138
|
+
# Dispatch controller chain for the current path
|
123
139
|
request_ctx.env = env
|
124
140
|
result = ::Tanuki::ControllerBehavior.dispatch(request_ctx, ctx.i18n ? ::Tanuki::I18n : ctx.root_page,
|
125
141
|
Rack::Utils.unescape(env['PATH_INFO']).force_encoding('UTF-8'))
|
142
|
+
|
143
|
+
# Handle dispatch result
|
126
144
|
case result[:type]
|
127
145
|
when :redirect then
|
128
146
|
[302, {'Location' => result[:location], 'Content-Type' => 'text/html; charset=utf-8'}, []]
|
@@ -131,12 +149,14 @@ module Tanuki
|
|
131
149
|
else
|
132
150
|
[404, {'Content-Type' => 'text/html; charset=utf-8'}, build_body(result[:controller], request_ctx)]
|
133
151
|
end
|
134
|
-
|
152
|
+
|
153
|
+
end # if
|
154
|
+
|
135
155
|
end
|
136
156
|
end
|
137
157
|
|
138
|
-
end #
|
158
|
+
end # class << self
|
139
159
|
|
140
|
-
end #
|
160
|
+
end # Application
|
141
161
|
|
142
|
-
end #
|
162
|
+
end # Tanuki
|
data/lib/tanuki/argument/base.rb
CHANGED