tanuki 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/LICENSE +1 -1
  2. data/README.rdoc +10 -2
  3. data/app/tanuki/attribute/attribute.rb +2 -2
  4. data/app/tanuki/base/base.rb +2 -2
  5. data/app/tanuki/controller/controller.rb +2 -2
  6. data/app/tanuki/controller/default.thtml +1 -1
  7. data/app/tanuki/controller/index.thtml +1 -1
  8. data/app/tanuki/controller/link.thtml +1 -1
  9. data/app/tanuki/manager/controller/controller.rb +2 -0
  10. data/app/tanuki/manager/page/page.rb +2 -0
  11. data/app/tanuki/meta_model/manager.ttxt +1 -1
  12. data/app/tanuki/meta_model/manager_base.ttxt +2 -2
  13. data/app/tanuki/meta_model/meta_model.rb +2 -2
  14. data/app/tanuki/meta_model/model.ttxt +1 -1
  15. data/app/tanuki/meta_model/model_base.ttxt +2 -2
  16. data/app/tanuki/model/controller/controller.rb +2 -0
  17. data/app/tanuki/model/model.rb +2 -2
  18. data/app/tanuki/model/page/page.rb +2 -0
  19. data/app/tanuki/page/missing/default.thtml +1 -1
  20. data/app/tanuki/page/missing/missing.rb +2 -2
  21. data/app/user/page/index/default.thtml +1 -1
  22. data/app/user/page/index/index.rb +2 -2
  23. data/bin/tanuki +3 -201
  24. data/config/common.rb +1 -1
  25. data/config/common_application.rb +3 -3
  26. data/config/development_application.rb +1 -1
  27. data/config/production_application.rb +1 -1
  28. data/config/test_application.rb +2 -0
  29. data/lib/tanuki/application.rb +27 -7
  30. data/lib/tanuki/argument/base.rb +3 -3
  31. data/lib/tanuki/argument/integer.rb +3 -3
  32. data/lib/tanuki/argument/integer_range.rb +3 -3
  33. data/lib/tanuki/argument/string.rb +3 -3
  34. data/lib/tanuki/argument.rb +3 -3
  35. data/lib/tanuki/behavior/controller_behavior.rb +40 -8
  36. data/lib/tanuki/behavior/meta_model_behavior.rb +62 -20
  37. data/lib/tanuki/behavior/model_behavior.rb +4 -4
  38. data/lib/tanuki/behavior/object_behavior.rb +2 -2
  39. data/lib/tanuki/configurator.rb +2 -2
  40. data/lib/tanuki/context.rb +8 -3
  41. data/lib/tanuki/extensions/module.rb +16 -1
  42. data/lib/tanuki/extensions/rack/builder.rb +2 -2
  43. data/lib/tanuki/extensions/rack/server.rb +2 -2
  44. data/lib/tanuki/extensions/rack/static_dir.rb +2 -2
  45. data/lib/tanuki/i18n.rb +2 -2
  46. data/lib/tanuki/launcher.rb +2 -2
  47. data/lib/tanuki/loader.rb +24 -4
  48. data/lib/tanuki/model_generator.rb +114 -0
  49. data/lib/tanuki/template_compiler.rb +89 -13
  50. data/lib/tanuki/utility/create.rb +38 -0
  51. data/lib/tanuki/utility/generate.rb +52 -0
  52. data/lib/tanuki/utility/help.rb +16 -0
  53. data/lib/tanuki/utility/server.rb +23 -0
  54. data/lib/tanuki/utility/version.rb +15 -0
  55. data/lib/tanuki/utility.rb +65 -0
  56. data/lib/tanuki/version.rb +2 -2
  57. data/lib/tanuki.rb +1 -2
  58. data/schema/tanuki/l10n/en/controller.yml +1 -1
  59. data/schema/tanuki/l10n/en/page.yml +1 -1
  60. data/schema/tanuki/l10n/ru/controller.yml +1 -1
  61. data/schema/tanuki/l10n/ru/page.yml +1 -1
  62. data/schema/tanuki/models/controller.yml +1 -1
  63. data/schema/tanuki/models/page.yml +1 -1
  64. metadata +16 -5
  65. 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
- == Resources
20
+ == Hack on the Core
21
21
 
22
- {Home Page}[http://withballs.org]
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
@@ -1,4 +1,4 @@
1
- class Tanuki_Attribute
1
+ class Tanuki::Attribute
2
2
  def initialize(cfg, owner)
3
3
  #--
4
4
  # created on demand (first access)
@@ -16,4 +16,4 @@ class Tanuki_Attribute
16
16
  def value
17
17
  # value of data (scalar, array, or hash)
18
18
  end
19
- end
19
+ end
@@ -1,3 +1,3 @@
1
- class Tanuki_Base
1
+ class Tanuki::Base
2
2
  include Tanuki::BaseBehavior
3
- end
3
+ end
@@ -1,3 +1,3 @@
1
- class Tanuki_Controller < Tanuki_Base
1
+ class Tanuki::Controller < Tanuki::Base
2
2
  include Tanuki::ControllerBehavior
3
- end
3
+ end
@@ -2,4 +2,4 @@
2
2
  <%! visual_child.default_view -%>
3
3
  % else
4
4
  <%! index_view -%>
5
- % end
5
+ % end
@@ -1 +1 @@
1
- <%= self.class %> is under construction
1
+ <%= self.class %> is under construction
@@ -4,4 +4,4 @@
4
4
  <a class="active" href="<%= self.link %>"><%= self %></a>
5
5
  % else
6
6
  <a href="<%= self.link %>"><%= self %></a>
7
- % end
7
+ % end
@@ -0,0 +1,2 @@
1
+ class Tanuki::Manager::Controller
2
+ end
@@ -0,0 +1,2 @@
1
+ class Tanuki::Manager::Page
2
+ end
@@ -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 %> < Tanuki_Controller
2
- end
1
+ class <%= class_name_for :manager_base %> < Tanuki::Controller
2
+ end
@@ -1,3 +1,3 @@
1
- class Tanuki_MetaModel < Tanuki_Base
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 %> < Tanuki_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
@@ -0,0 +1,2 @@
1
+ class Tanuki::Model::Controller
2
+ end
@@ -1,3 +1,3 @@
1
- class Tanuki_Model
1
+ class Tanuki::Model
2
2
  include Tanuki::ModelBehavior
3
- end
3
+ end
@@ -0,0 +1,2 @@
1
+ class Tanuki::Model::Page
2
+ end
@@ -58,4 +58,4 @@
58
58
  % end
59
59
  </div>
60
60
  </body>
61
- </html>
61
+ </html>
@@ -1,4 +1,4 @@
1
- class Tanuki_Page_Missing < Tanuki_Controller
1
+ class Tanuki::Page::Missing < Tanuki::Controller
2
2
  def visual_parent
3
3
  nil
4
4
  end
@@ -6,4 +6,4 @@ class Tanuki_Page_Missing < Tanuki_Controller
6
6
  def result_type
7
7
  :not_found
8
8
  end
9
- end
9
+ end
@@ -118,4 +118,4 @@
118
118
  </table></div>
119
119
  </div>
120
120
  </body>
121
- </html>
121
+ </html>
@@ -1,2 +1,2 @@
1
- class User_Page_Index < Tanuki_Controller
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
- module Tanuki
3
-
4
- module Utility
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
@@ -4,4 +4,4 @@ set :gen_root, proc { File.join(root, 'gen') }
4
4
  set :schema_root, proc { File.join(root, 'schema') }
5
5
 
6
6
  # Cache
7
- set :templates, {}
7
+ set :templates, {}
@@ -11,8 +11,8 @@ set :port, 3000
11
11
  set :development, false
12
12
 
13
13
  # Default controllers
14
- set :root_page, ::User_Page_Index
15
- set :missing_page, ::Tanuki_Page_Missing
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
@@ -5,4 +5,4 @@ set :development, true
5
5
  use Rack::CommonLogger
6
6
  use Rack::Lint
7
7
  use Rack::Reloader, 0
8
- use Rack::ShowExceptions
8
+ use Rack::ShowExceptions
@@ -1,2 +1,2 @@
1
1
  load_config :common_application
2
- set :development, false
2
+ set :development, false
@@ -0,0 +1,2 @@
1
+ load_config :development_application
2
+ set :root_page, ::Test::Page::Index
@@ -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
- puts "A#{'n' if @environment =~ /\A[aeiou]/} #{@environment} Tanuki appears! Press Ctrl-C to set it free.",
59
- "You used #{@context.running_server.name.gsub(/.*::/, '')} at #{@context.host}:#{@context.port}."
60
- @context.running_server.run rack_builder.to_app, :Host => @context.host, :Port => @context.port
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
- end
152
+
153
+ end # if
154
+
135
155
  end
136
156
  end
137
157
 
138
- end # end class << self
158
+ end # class << self
139
159
 
140
- end # end Application
160
+ end # Application
141
161
 
142
- end # end Tanuki
162
+ end # Tanuki
@@ -21,7 +21,7 @@ module Tanuki
21
21
  @value = to_value(obj)
22
22
  end
23
23
 
24
- end # end Base
24
+ end # Base
25
25
 
26
- end # end Argument
27
- end # end Tanuki
26
+ end # Argument
27
+ end # Tanuki
@@ -9,7 +9,7 @@ module Tanuki
9
9
  begin Kernel::Integer obj rescue @default end
10
10
  end
11
11
 
12
- end # end Integer
12
+ end # Integer
13
13
 
14
- end # end Argument
15
- end # end Tanuki
14
+ end # Argument
15
+ end # Tanuki
@@ -16,7 +16,7 @@ module Tanuki
16
16
  @range.include?(i) ? i : @default
17
17
  end
18
18
 
19
- end # end IntegerRange
19
+ end # IntegerRange
20
20
 
21
- end # end Argument
22
- end # end Tanuki
21
+ end # Argument
22
+ end # Tanuki
@@ -9,7 +9,7 @@ module Tanuki
9
9
  obj.to_s
10
10
  end
11
11
 
12
- end # end String
12
+ end # String
13
13
 
14
- end # end Argument
15
- end # end Tanuki
14
+ end # Argument
15
+ end # Tanuki
@@ -34,8 +34,8 @@ module Tanuki
34
34
  end
35
35
  end
36
36
 
37
- end # end class << self
37
+ end # class << self
38
38
 
39
- end # end Argument
39
+ end # Argument
40
40
 
41
- end # end Tanuki
41
+ end # Tanuki