tanuki 0.1.3 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.rdoc +6 -3
  2. data/app/tanuki/attribute/attribute.rb +19 -0
  3. data/app/tanuki/base/base.rb +3 -0
  4. data/app/tanuki/controller/controller.rb +1 -1
  5. data/app/tanuki/controller/link.thtml +6 -6
  6. data/app/tanuki/meta_model/manager.ttxt +2 -0
  7. data/app/tanuki/meta_model/manager_base.ttxt +2 -0
  8. data/app/tanuki/meta_model/meta_model.rb +3 -0
  9. data/app/tanuki/meta_model/model.ttxt +2 -0
  10. data/app/tanuki/meta_model/model_base.ttxt +12 -0
  11. data/app/tanuki/model/model.rb +3 -0
  12. data/app/tanuki/page/missing/default.thtml +61 -2
  13. data/app/user/page/index/default.thtml +120 -120
  14. data/app/user/page/index/index.rb +1 -1
  15. data/bin/tanuki +185 -53
  16. data/config/common.rb +7 -0
  17. data/config/common_application.rb +31 -0
  18. data/config/development_application.rb +8 -0
  19. data/config/production_application.rb +2 -0
  20. data/lib/tanuki/application.rb +15 -19
  21. data/lib/tanuki/argument/base.rb +2 -2
  22. data/lib/tanuki/argument/integer.rb +2 -2
  23. data/lib/tanuki/argument/integer_range.rb +3 -3
  24. data/lib/tanuki/argument/string.rb +2 -2
  25. data/lib/tanuki/argument.rb +3 -3
  26. data/lib/tanuki/{controller_behavior.rb → behavior/controller_behavior.rb} +22 -21
  27. data/lib/tanuki/behavior/meta_model_behavior.rb +43 -0
  28. data/lib/tanuki/behavior/model_behavior.rb +112 -0
  29. data/lib/tanuki/{object_behavior.rb → behavior/object_behavior.rb} +6 -6
  30. data/lib/tanuki/configurator.rb +39 -76
  31. data/lib/tanuki/context.rb +31 -19
  32. data/lib/tanuki/{module_extensions.rb → extensions/module.rb} +3 -3
  33. data/lib/tanuki/extensions/object.rb +12 -0
  34. data/lib/tanuki/extensions/rack/static_dir.rb +18 -0
  35. data/lib/tanuki/i18n.rb +3 -1
  36. data/lib/tanuki/launcher.rb +3 -2
  37. data/lib/tanuki/loader.rb +37 -46
  38. data/lib/tanuki/template_compiler.rb +8 -7
  39. data/lib/tanuki/version.rb +1 -1
  40. data/lib/tanuki.rb +14 -8
  41. data/schema/tanuki/models/controller.yml +2 -3
  42. data/schema/tanuki/models/page.yml +7 -8
  43. metadata +35 -27
  44. data/app/tanuki/object/object.rb +0 -3
@@ -0,0 +1,31 @@
1
+ load_config :common
2
+
3
+ # Rack middleware
4
+ use Rack::Head
5
+ use Rack::StaticDir, 'public'
6
+
7
+ # Server
8
+ set :server, [:thin, :mongrel, :webrick]
9
+ set :host, '0.0.0.0'
10
+ set :port, 3000
11
+
12
+ # Default controllers
13
+ set :root_page, ::User_Page_Index
14
+ set :missing_page, ::Tanuki_Page_Missing
15
+
16
+ # Internationalization
17
+ set :i18n, false
18
+ set :language, nil
19
+ set :language_fallback, {}
20
+ set :languages, proc { language_fallback.keys }
21
+ set :best_language, proc {|lngs| language_fallback[language].each {|lng| return lng if lngs.include? lng }; nil }
22
+ set :best_translation, proc {|trn| language_fallback[language].each {|lng| return trn[lng] if trn.include? lng }; nil }
23
+
24
+ # Visitors
25
+ visitor :string do s = ''; proc {|out| s << out.to_s } end
26
+
27
+ # Argument associations
28
+ argument Fixnum, Argument::Integer
29
+ argument Bignum, Argument::Integer
30
+ argument Range, Argument::IntegerRange
31
+ argument String, Argument::String
@@ -0,0 +1,8 @@
1
+ load_config :common_application
2
+ set :development, true
3
+
4
+ # Rack middleware
5
+ use Rack::CommonLogger
6
+ use Rack::Lint
7
+ use Rack::Reloader, 0
8
+ use Rack::ShowExceptions
@@ -0,0 +1,2 @@
1
+ load_config :common_application
2
+ set :development, false
@@ -4,37 +4,33 @@ module Tanuki
4
4
  # It contains core application functionality like configuration, request handling and view management.
5
5
  class Application
6
6
 
7
- @context = Loader.context = Context.new
8
- @rack_middleware = {}
7
+ @context = (Loader.context = Context).child
8
+ @rack_middleware = []
9
9
 
10
10
  class << self
11
11
 
12
- # Removes a given middleware from the Rack middleware pipeline
12
+ # Removes all occurences of a given +middleware+ from the Rack middleware pipeline.
13
13
  def discard(middleware)
14
- @rack_middleware.delete(middleware)
14
+ @rack_middleware.delete_if {|item| item[0] == middleware }
15
15
  end
16
16
 
17
- # Runs the application with current settings
17
+ # Runs the application with current settings.
18
18
  def run
19
19
  rack_builder = Rack::Builder.new
20
- @rack_middleware.each {|middleware, params| rack_builder.use(middleware, *params[0], &params[1]) }
20
+ @rack_middleware.each {|item| rack_builder.use(item[0], *item[1], &item[2]) }
21
21
  rack_builder.run(rack_app)
22
22
  srv = available_server
23
- puts "A wild Tanuki appears!", "You used #{srv.name.gsub(/.*::/, '')} at #{@context.host}:#{@context.port}."
23
+ puts "A wild Tanuki appears! Press Ctrl-C to set it free.",
24
+ "You used #{srv.name.gsub(/.*::/, '')} at #{@context.host}:#{@context.port}."
24
25
  srv.run rack_builder.to_app, :Host => @context.host, :Port => @context.port
25
26
  end
26
27
 
27
- # Sets an option to value in the current context.
28
- def set(option, value)
29
- @context.send("#{option}=".to_sym, value)
30
- end
31
-
32
- # Adds a given middleware to the Rack middleware pipeline
28
+ # Adds a given +middleware+ with optional +args+ and +block+ to the Rack middleware pipeline.
33
29
  def use(middleware, *args, &block)
34
- @rack_middleware[middleware] = [args, block]
30
+ @rack_middleware << [middleware, args, block]
35
31
  end
36
32
 
37
- # Adds a template visitor block. This block must return a Proc.
33
+ # Adds a template visitor +block+. This +block+ must return a +Proc+.
38
34
  #
39
35
  # visitor :escape do
40
36
  # s = ''
@@ -50,7 +46,7 @@ module Tanuki
50
46
  # <%_escape escaped_view %>
51
47
  # <%_printf('<div>%s</div>') formatted_view %>
52
48
  def visitor(sym, &block)
53
- ObjectBehavior.instance_eval { define_method "#{sym}_visitor".to_sym, &block }
49
+ BaseBehavior.instance_eval { define_method "#{sym}_visitor".to_sym, &block }
54
50
  end
55
51
 
56
52
  private
@@ -67,7 +63,7 @@ module Tanuki
67
63
  raise "servers #{@context.server.join(', ')} not found"
68
64
  end
69
65
 
70
- # Returns an array of template outputs for controller ctrl in context ctx.
66
+ # Returns an array of template outputs for controller +ctrl+ in context +request_ctx+.
71
67
  def build_body(ctrl, request_ctx)
72
68
  arr = []
73
69
  Launcher.new(ctrl, request_ctx).each &proc {|out| arr << out.to_s }
@@ -84,14 +80,14 @@ module Tanuki
84
80
  proc do |env|
85
81
  request_ctx = ctx.child
86
82
  request_ctx.templates = {}
87
- if match = env['REQUEST_PATH'].match(/^(.+)(?<!\$)\/$/)
83
+ if match = env['PATH_INFO'].match(/^(.+)(?<!\$)\/$/)
88
84
  loc = match[1]
89
85
  loc << "?#{env['QUERY_STRING']}" unless env['QUERY_STRING'].empty?
90
86
  [301, {'Location' => loc, 'Content-Type' => 'text/html; charset=utf-8'}, []]
91
87
  else
92
88
  request_ctx.env = env
93
89
  result = ::Tanuki::ControllerBehavior.dispatch(request_ctx, ctx.i18n ? ::Tanuki::I18n : ctx.root_page,
94
- Rack::Utils.unescape(env['REQUEST_PATH']).force_encoding('UTF-8'))
90
+ Rack::Utils.unescape(env['PATH_INFO']).force_encoding('UTF-8'))
95
91
  case result[:type]
96
92
  when :redirect then
97
93
  [302, {'Location' => result[:location], 'Content-Type' => 'text/html; charset=utf-8'}, []]
@@ -6,7 +6,7 @@ module Tanuki
6
6
 
7
7
  attr_reader :default, :value
8
8
 
9
- # Initializes the argument with a default value.
9
+ # Initializes the argument with a +default+ value.
10
10
  def initialize(default)
11
11
  @value = @default = default
12
12
  end
@@ -16,7 +16,7 @@ module Tanuki
16
16
  @value.to_s
17
17
  end
18
18
 
19
- # Sets the value with required rules.
19
+ # Sets the value to +obj+ with required rules.
20
20
  def value=(obj)
21
21
  @value = to_value(obj)
22
22
  end
@@ -1,10 +1,10 @@
1
1
  module Tanuki
2
2
  module Argument
3
3
 
4
- # Tanuki::Argument::Integer is a class for Integer arguments.
4
+ # Tanuki::Argument::Integer is a class for +Integer+ arguments.
5
5
  class Integer < Base
6
6
 
7
- # Returns argument value from a string representation.
7
+ # Returns argument value from an object +obj+.
8
8
  def to_value(obj)
9
9
  begin Kernel::Integer obj rescue @default end
10
10
  end
@@ -1,16 +1,16 @@
1
1
  module Tanuki
2
2
  module Argument
3
3
 
4
- # Tanuki::Argument::IntegerRange is a class for Integer arguments with a certain value range.
4
+ # Tanuki::Argument::IntegerRange is a class for +Integer+ arguments with a certain value range.
5
5
  class IntegerRange < Integer
6
6
 
7
- # Initializes the argument with a default value and allowed value range.
7
+ # Initializes the argument with a +default+ value and allowed value +range+.
8
8
  def initialize(range, default=nil)
9
9
  super(default ? default : range.first)
10
10
  @range = range
11
11
  end
12
12
 
13
- # Returns argument value from a string representation.
13
+ # Returns argument value from an object +obj+.
14
14
  def to_value(obj)
15
15
  i = super(obj)
16
16
  @range.include?(i) ? i : @default
@@ -1,10 +1,10 @@
1
1
  module Tanuki
2
2
  module Argument
3
3
 
4
- # Tanuki::Argument::String is a class for String arguments.
4
+ # Tanuki::Argument::String is a class for +String+ arguments.
5
5
  class String < Base
6
6
 
7
- # Returns argument value from a string representation.
7
+ # Returns argument value from an object +obj+.
8
8
  def to_value(obj)
9
9
  obj.to_s
10
10
  end
@@ -12,12 +12,12 @@ module Tanuki
12
12
 
13
13
  class << self
14
14
 
15
- # Remove argument association for a given type class.
15
+ # Removes argument association for a given type class +klass+.
16
16
  def delete(klass)
17
17
  @assoc.delete(klass)
18
18
  end
19
19
 
20
- # Associate a given type class with an argument class.
20
+ # Associates a given type class +klass+ with an argument class +arg_class+.
21
21
  def store(klass, arg_class)
22
22
  warn "Tanuki::Argument::Base is not an ancestor of `#{arg_class}'" unless arg_class.ancestors.include? Argument::Base
23
23
  @assoc[klass] = arg_class
@@ -25,7 +25,7 @@ module Tanuki
25
25
 
26
26
  alias_method :[], :store
27
27
 
28
- # Convert a given type object to an argument object.
28
+ # Converts a given type object +obj+ to an argument object with optional +args+.
29
29
  def to_argument(obj, *args)
30
30
  if @assoc.include?(klass = obj.class)
31
31
  @assoc[klass].new(obj, *args)
@@ -9,7 +9,7 @@ module Tanuki
9
9
  internal_attr_reader :model, :logical_parent, :link
10
10
  internal_attr_accessor :logical_child, :visual_child
11
11
 
12
- # Create new controller with context ctx, logical_parent controller, route_part definitions and a model.
12
+ # Creates new controller with context +ctx+, +logical_parent+ controller, +route_part+ definitions and a +model+.
13
13
  def initialize(ctx, logical_parent, route_part, model=nil)
14
14
  @_configured = false
15
15
  @_ctx = ctx
@@ -29,7 +29,7 @@ module Tanuki
29
29
  end
30
30
  end
31
31
 
32
- # Invoked with route args when current route is initialized.
32
+ # Invoked with route +args+ when current route is initialized.
33
33
  def initialize_route(*args)
34
34
  end
35
35
 
@@ -38,7 +38,7 @@ module Tanuki
38
38
  @_ctx
39
39
  end
40
40
 
41
- # Initializes and retrieves child route object. Searches static, dynamic, and ghost routes (in that order).
41
+ # Initializes and retrieves child controller on +route+. Searches static, dynamic, and ghost routes (in that order).
42
42
  def [](route, *args)
43
43
  byname = (args.length == 1 and args[0].is_a? Hash)
44
44
  ensure_configured!
@@ -77,12 +77,12 @@ module Tanuki
77
77
  @_cache[key] = child # Thread safe (possible overwrite, but within consistent state)
78
78
  end
79
79
 
80
- # Return true, if controller is active.
80
+ # Returns true, if controller is active.
81
81
  def active?
82
82
  @_active
83
83
  end
84
84
 
85
- # Retrieves child route class. Searches static, dynamic, and ghost routes (in that order).
85
+ # Retrieves child controller class on +route+. Searches static, dynamic, and ghost routes (in that order).
86
86
  def child_class(route)
87
87
  ensure_configured!
88
88
  args = []
@@ -108,11 +108,11 @@ module Tanuki
108
108
  end
109
109
  end
110
110
 
111
- # Invoked when controller need to be configured.
111
+ # Invoked when controller needs to be configured.
112
112
  def configure
113
113
  end
114
114
 
115
- # Return true, if controller is current.
115
+ # Returns true, if controller is current.
116
116
  def current?
117
117
  @_current
118
118
  end
@@ -122,6 +122,7 @@ module Tanuki
122
122
  nil
123
123
  end
124
124
 
125
+ # Calls +block+ once for each visible child controller on static or dynamic routes, passing it as a parameter.
125
126
  def each(&block)
126
127
  return Enumerator.new(self) unless block_given?
127
128
  ensure_configured!
@@ -157,15 +158,15 @@ module Tanuki
157
158
  nil
158
159
  end
159
160
 
160
- # Returns the link to the current controller, switching the active controller on the respective path level to self.
161
+ # Returns the link to the current controller, switching the active controller on the respective path level to +self+.
161
162
  def forward_link
162
- uri_parts = @_ctx.env['REQUEST_PATH'].split(/(?<!\$)\//)
163
+ uri_parts = @_ctx.env['PATH_INFO'].split(/(?<!\$)\//)
163
164
  link_parts = link.split(/(?<!\$)\//)
164
165
  link_parts.each_index {|i| uri_parts[i] = link_parts[i] }
165
166
  uri_parts.join('/') << ((qs = @_ctx.env['QUERY_STRING']).empty? ? '' : "?#{qs}")
166
167
  end
167
168
 
168
- # Returns the number of children.
169
+ # Returns the number of visible child controllers on static and dynamic routes.
169
170
  def length
170
171
  if @_child_collection_defs.length > 0
171
172
  if @_length_is_valid
@@ -179,7 +180,7 @@ module Tanuki
179
180
  end
180
181
  end
181
182
 
182
- # Process context passed to child
183
+ # Invoked when child controller context needs to be processed before initializing.
183
184
  def process_child_context(ctx, route)
184
185
  ctx
185
186
  end
@@ -198,21 +199,21 @@ module Tanuki
198
199
 
199
200
  private
200
201
 
201
- # Defines a child of class klass on route with model, optionally hidden.
202
+ # Defines a child of class +klass+ on +route+ with +model+, optionally +hidden+.
202
203
  def has_child(klass, route, model=nil, hidden=false)
203
204
  @_child_defs[route] = {:class => klass, :model => model, :hidden => hidden}
204
205
  @_length += 1 unless hidden
205
206
  self
206
207
  end
207
208
 
208
- # Defines a child collection of type parse_regexp.
209
+ # Defines a child collection of type +parse_regexp+, formatted back by +format_string+.
209
210
  def has_child_collection(parse_regexp, format_string, child_def_fetcher)
210
211
  @_child_defs[parse_regexp] = @_child_collection_defs.size
211
212
  @_child_collection_defs << {:parse => parse_regexp, :format => format_string, :fetcher => child_def_fetcher}
212
213
  @_length_is_valid = false
213
214
  end
214
215
 
215
- # Invoked for route with args when a route is missing.
216
+ # Invoked for +route+ with +args+ when a route is missing. This hook can be used to make ghost routes.
216
217
  def missing_route(route, *args)
217
218
  @_ctx.missing_page.new(@_ctx, self, {:route => route, :args => []})
218
219
  end
@@ -225,12 +226,12 @@ module Tanuki
225
226
  @_arg_defs ||= superclass.arg_defs.dup
226
227
  end
227
228
 
228
- # Escapes a given string for use in links.
229
+ # Escapes characters +chrs+ and encodes a given string +s+ for use in links.
229
230
  def escape(s, chrs)
230
231
  s ? Rack::Utils.escape(s.to_s.gsub(/[\$#{chrs}]/, '$\0')) : nil
231
232
  end
232
233
 
233
- # Extracts arguments, initializing default values beforehand. Searches md hash for default value overrides.
234
+ # Extracts arguments, initializing default values beforehand. Searches +md+ hash for default value overrides.
234
235
  def extract_args(md)
235
236
  res = []
236
237
  arg_defs.each_pair do |name, arg|
@@ -239,7 +240,7 @@ module Tanuki
239
240
  res
240
241
  end
241
242
 
242
- # Builds link from root to self.
243
+ # Builds link from controller +ctrl+ to a given route.
243
244
  def grow_link(ctrl, route_part, arg_defs)
244
245
  own_link = escape(route_part[:route], '\/:') << route_part[:args].map do |k, v|
245
246
  arg_defs[k][:arg].default == v ? '' : ":#{escape(k, '\/:-')}-#{escape(v, '\/:')}"
@@ -247,7 +248,7 @@ module Tanuki
247
248
  "#{ctrl.link == '/' ? '' : ctrl.link}/#{own_link}"
248
249
  end
249
250
 
250
- # Defines an argument with name, derived from object obj with additional args.
251
+ # Defines an argument with a +name+, derived from type +obj+ with additional +args+.
251
252
  def has_arg(name, obj, *args)
252
253
  # TODO Ensure thread safety
253
254
  arg_defs[name] = {:arg => Argument.to_argument(obj, *args), :index => @_arg_defs.size}
@@ -264,7 +265,7 @@ module Tanuki
264
265
 
265
266
  class << self
266
267
 
267
- # Dispathes route chain in context ctx on request_path, starting with controller klass.
268
+ # Dispathes route chain in context +ctx+ on +request_path+, starting with controller +klass+.
268
269
  def dispatch(ctx, klass, request_path)
269
270
  parts = parse_path(request_path)
270
271
  curr = root_ctrl = klass.new(ctx, nil, nil, true)
@@ -297,7 +298,7 @@ module Tanuki
297
298
 
298
299
  private
299
300
 
300
- # Parses path to return route name and arguments.
301
+ # Parses +path+ to return route name and arguments.
301
302
  def parse_path(path)
302
303
  path[1..-1].split(/(?<!\$)\//).map do |s|
303
304
  arr = s.gsub('$/', '/').split(/(?<!\$):/)
@@ -312,7 +313,7 @@ module Tanuki
312
313
  end
313
314
  end
314
315
 
315
- # Unescape a given link part for internal use.
316
+ # Unescapes a given link part for internal use.
316
317
  def unescape(s)
317
318
  s ? s.gsub(/\$([\/\$:-])/, '\1') : nil
318
319
  end
@@ -0,0 +1,43 @@
1
+ module Tanuki
2
+
3
+ module MetaModelBehavior
4
+
5
+ def initialize(namespace, name, data)
6
+ @namespace = namespace
7
+ @name = name
8
+ @data = data
9
+ end
10
+
11
+ def class_name_for(class_type)
12
+ case class_type
13
+ when :model, :model_base then "#{@namespace}_Model_#{@name}"
14
+ when :manager, :manager_base then "#{@namespace}_Manager_#{@name}"
15
+ end
16
+ end
17
+
18
+ def key
19
+ if @data['key'].nil?
20
+ []
21
+ elsif @data['key'].is_a? Array
22
+ @data['key'].map {|item| qualified_name(item) }
23
+ elsif @data['key'].is_a? String
24
+ [qualified_name(@data['key'])]
25
+ else
26
+ raise "key for model #{@namespace}.#{@name} is invalid"
27
+ end
28
+ end
29
+
30
+ def qualified_name(field_name)
31
+ parts = field_name.split('.')
32
+ if parts.length == 1
33
+ ":#{field_name}"
34
+ elsif parts.length == 2
35
+ ":#{parts[1]}.qualify(:#{parts[0]}"
36
+ else
37
+ raise "field name for model #{@namespace}.#{@name} is invalid"
38
+ end
39
+ end
40
+
41
+ end # end MetaModelBehavior
42
+
43
+ end # end Tanuki
@@ -0,0 +1,112 @@
1
+ module Tanuki
2
+
3
+ module ModelBehavior
4
+
5
+ def initialize(data = {}, lazy = false)
6
+ @_data = data
7
+ @_loaded = !lazy
8
+ end
9
+
10
+ def [](attribute)
11
+ ensure_loaded!
12
+ self.class[attribute].get(@_data)
13
+ end
14
+
15
+ def []=(attribute, value)
16
+ @_errors ||= {}
17
+ @_original ||= {}
18
+ begin
19
+ @_original[attribute] = self[attribute] unless @_original.include? attribute
20
+ self.class[attribute].set(@_data, value)
21
+ @_errors.delete(attribute)
22
+ rescue
23
+ @_errors[attribute] = {:value => value, :error => $!}
24
+ end
25
+ end
26
+
27
+ def internals_get(attribute)
28
+ self.class[attribute].internals_get(@_data)
29
+ end
30
+
31
+ def internals_set(attribute, internal_value)
32
+ @_errors ||= {}
33
+ internals_set(self.class[attribute], @_data)
34
+ end
35
+
36
+ def get_updates
37
+ @_original ||= {}
38
+ original_data = {}
39
+ self.class.attributes.each_pair do |name, attrib|
40
+ attrib.set(original_data, @_original[name])
41
+ end
42
+ updates = {}
43
+ original_data.each_pair do |field, value|
44
+ updates[field] = data[field] if data[field] != original_data[field]
45
+ end
46
+ updates
47
+ end
48
+
49
+ def get_error(attribute)
50
+ @_errors ||= {}
51
+ @_errors[attribute]
52
+ end
53
+
54
+ def invalid?(attribute)
55
+ @_errors.include? attribute
56
+ end
57
+
58
+ def has_errors?
59
+ @_errors ||= {}
60
+ @_errors == {}
61
+ end
62
+
63
+ def errors
64
+ @_errors ||= {}
65
+ @_errors
66
+ end
67
+
68
+ module ClassMethods
69
+
70
+ def create(data, ctx, lazy = false) # IDENTITY TRACKING AND LAZY LOADING
71
+ entity_key = extract_key(data)
72
+ key = [self, entity_key] #extract_key is generated ad hoc by model compiler!
73
+ if cached = ctx.entity_cache[key]
74
+ cached
75
+ else
76
+ ctx.entity_cache[key] = get(*entity_key) # get is generated Ad Hoc by model compiler
77
+ end
78
+ end
79
+
80
+ def has_attribute(attribute, attr_def)
81
+ @_attributes ||= superclass.instance_variable_get(:@_attributes).dup
82
+ @_attributes[attribute] = attr_def
83
+ end
84
+
85
+ def [](attribute)
86
+ @_attributes[attribute]
87
+ end
88
+
89
+ def has_reference(attribute, reference_def)
90
+ @_references ||= superclass.instance_variable_get(:@_references).dup
91
+ @_references[attribute] = reference_def
92
+ end
93
+
94
+ # Prepares the extended module.
95
+ def self.extended(mod)
96
+ mod.instance_variable_set(:@_attributes, {})
97
+ mod.instance_variable_set(:@_references, {})
98
+ end
99
+
100
+ end # end ClassMethods
101
+
102
+ class << self
103
+
104
+ def included(mod)
105
+ mod.extend ClassMethods
106
+ end
107
+
108
+ end # end class << self
109
+
110
+ end # end ModelBehaviour
111
+
112
+ end # end Tanuki
@@ -1,15 +1,15 @@
1
1
  module Tanuki
2
2
 
3
- # Tanuki::ControllerBehavior contains basic methods for a framework object.
3
+ # Tanuki::BaseBehavior contains basic methods for a templatable object.
4
4
  # In is included in the base framework object class.
5
- module ObjectBehavior
5
+ module BaseBehavior
6
6
 
7
- # Shortcut to Tanuki::Loader.has_template?. Used internally by templates.
7
+ # Shortcut to Tanuki::Loader::has_template?. Used internally by templates.
8
8
  def _has_tpl(ctx, klass, sym)
9
9
  Tanuki::Loader.has_template?(ctx.templates, klass, sym)
10
10
  end
11
11
 
12
- # Shortcut to Tanuki::Loader.run_template. Used internally by templates.
12
+ # Shortcut to Tanuki::Loader::run_template. Used internally by templates.
13
13
  def _run_tpl(ctx, obj, sym, *args, &block)
14
14
  Tanuki::Loader.run_template(ctx.templates, obj, sym, *args, &block)
15
15
  end
@@ -19,7 +19,7 @@ module Tanuki
19
19
  ctx
20
20
  end
21
21
 
22
- # Kernel#method_missing hook for fetching views.
22
+ # Allows to return template blocks. E. g. returns +foobar+ template block when +foobar_view+ method is called.
23
23
  def method_missing(sym, *args, &block)
24
24
  if matches = sym.to_s.match(/^(.*)_view$/)
25
25
  return Tanuki::Loader.run_template({}, self, matches[1].to_sym, *args, &block)
@@ -27,6 +27,6 @@ module Tanuki
27
27
  super
28
28
  end
29
29
 
30
- end # end ObjectBehavior
30
+ end # end BaseBehavior
31
31
 
32
32
  end # end Tanuki