manveru-innate 2009.04.01 → 2009.04.08
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +104 -0
- data/MANIFEST +18 -18
- data/Rakefile +3 -3
- data/example/app/retro_games.rb +6 -6
- data/example/app/todo/layout/default.erb +1 -1
- data/example/app/todo/view/index.erb +11 -11
- data/example/app/whywiki_erb/start.rb +1 -0
- data/example/app/whywiki_erb/view/{edit.html.erb → edit.erb} +0 -0
- data/example/app/whywiki_erb/view/{index.html.erb → index.erb} +0 -0
- data/example/howto_spec.rb +1 -1
- data/example/session.rb +3 -3
- data/innate.gemspec +3 -12
- data/lib/innate/action.rb +2 -1
- data/lib/innate/helper.rb +18 -27
- data/lib/innate/helper/cgi.rb +30 -20
- data/lib/innate/helper/render.rb +80 -0
- data/lib/innate/mock.rb +2 -3
- data/lib/innate/node.rb +79 -50
- data/lib/innate/options.rb +1 -1
- data/lib/innate/request.rb +3 -23
- data/lib/innate/spec.rb +3 -6
- data/lib/innate/version.rb +1 -1
- data/lib/innate/view/erb.rb +1 -1
- data/lib/innate/view/etanni.rb +2 -2
- data/lib/innate/view/none.rb +1 -1
- data/spec/innate/action/layout.rb +1 -1
- data/spec/innate/action/layout/file_layout.xhtml +1 -0
- data/spec/innate/helper/aspect.rb +6 -6
- data/spec/innate/helper/flash.rb +6 -6
- data/spec/innate/helper/render.rb +157 -0
- data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
- data/spec/innate/helper/view/locals.xhtml +1 -0
- data/spec/innate/helper/view/loop.xhtml +4 -0
- data/spec/innate/helper/view/num.xhtml +1 -0
- data/spec/innate/helper/view/partial.xhtml +1 -0
- data/spec/innate/helper/view/recursive.xhtml +7 -0
- data/spec/innate/node/node.rb +5 -13
- data/spec/innate/node/view/another_layout/{another_layout.erb → another_layout.xhtml} +1 -1
- data/spec/innate/node/view/{bar.erb → bar.xhtml} +0 -0
- data/spec/innate/node/view/foo.html.xhtml +1 -0
- data/spec/innate/node/view/{only_view.erb → only_view.xhtml} +0 -0
- data/spec/innate/node/view/with_layout.xhtml +1 -0
- data/spec/innate/provides.rb +2 -2
- data/spec/innate/provides/list.html.xhtml +1 -0
- data/spec/innate/provides/list.txt.xhtml +1 -0
- data/spec/innate/state/fiber.rb +8 -7
- data/tasks/bacon.rake +38 -21
- metadata +22 -51
- data/lib/innate/helper/partial.rb +0 -93
- data/spec/innate/action/layout/file_layout.erb +0 -1
- data/spec/innate/helper/partial.rb +0 -101
- data/spec/innate/helper/view/aspect_hello.erb +0 -1
- data/spec/innate/helper/view/locals.erb +0 -1
- data/spec/innate/helper/view/loop.erb +0 -4
- data/spec/innate/helper/view/num.erb +0 -1
- data/spec/innate/helper/view/partial.erb +0 -1
- data/spec/innate/helper/view/recursive.erb +0 -8
- data/spec/innate/node/view/foo.html.erb +0 -1
- data/spec/innate/node/view/with_layout.erb +0 -1
- data/spec/innate/provides/list.html.erb +0 -1
- data/spec/innate/provides/list.txt.erb +0 -1
data/lib/innate/helper/cgi.rb
CHANGED
@@ -6,36 +6,46 @@ module Innate
|
|
6
6
|
|
7
7
|
module Helper
|
8
8
|
module CGI
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Shortcut for Rack::Utils.escape
|
12
|
+
#
|
13
|
+
# @param [#to_s] input
|
14
|
+
# @return [String] URI-encoded representation of +input+
|
15
|
+
def url_encode(input)
|
16
|
+
Rack::Utils.escape(input.to_s)
|
12
17
|
end
|
18
|
+
alias u url_encode
|
13
19
|
|
14
|
-
#
|
15
|
-
|
16
|
-
|
20
|
+
# Shortcut for Rack::Utils.unescape
|
21
|
+
#
|
22
|
+
# @param [#to_s] input
|
23
|
+
# @return [String] URI-decoded representation of +input+
|
24
|
+
def url_decode(input)
|
25
|
+
Rack::Utils.unescape(input.to_s)
|
17
26
|
end
|
18
27
|
|
19
|
-
#
|
20
|
-
|
21
|
-
|
28
|
+
# Shortcut for Rack::Utils.escape_html
|
29
|
+
#
|
30
|
+
# @param [#to_s] input
|
31
|
+
# @return [String]
|
32
|
+
def html_escape(input)
|
33
|
+
Rack::Utils.escape_html(input.to_s)
|
22
34
|
end
|
23
35
|
|
24
|
-
#
|
25
|
-
|
26
|
-
|
36
|
+
# Shortcut for CGI.unescapeHTML
|
37
|
+
#
|
38
|
+
# @param [#to_s] input
|
39
|
+
# @return [String]
|
40
|
+
def html_unescape(input)
|
41
|
+
::CGI.unescapeHTML(input.to_s)
|
27
42
|
end
|
28
43
|
|
29
44
|
# safely escape all HTML and code
|
30
|
-
def
|
31
|
-
Rack::Utils.escape_html(
|
45
|
+
def html_and_code_escape(input)
|
46
|
+
Rack::Utils.escape_html(input.to_s).gsub(/#([{@$]@?)/, '#\1')
|
32
47
|
end
|
33
|
-
|
34
|
-
# one-letter versions help in case like #{h foo.inspect}
|
35
|
-
# ERb/ERuby/Rails compatible
|
36
|
-
alias u url_encode
|
37
|
-
|
38
|
-
module_function(:url_encode, :url_decode, :html_escape, :html_unescape, :h, :u)
|
48
|
+
alias h html_and_code_escape
|
39
49
|
end
|
40
50
|
end
|
41
51
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Innate
|
2
|
+
module Helper
|
3
|
+
module Render
|
4
|
+
# Enables you to simply call:
|
5
|
+
#
|
6
|
+
# @example of added functionality
|
7
|
+
# YourController.render_partial(:foo, :x => 42)
|
8
|
+
#
|
9
|
+
def self.included(into)
|
10
|
+
into.extend(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Renders the full action in the way a real request would.
|
14
|
+
#
|
15
|
+
# Please be aware that, if this is the first request from a client, you
|
16
|
+
# will not have access to the session in the action being rendered, as no
|
17
|
+
# actual session has been put into place yet.
|
18
|
+
#
|
19
|
+
# It should work as expected on any subsequent requests.
|
20
|
+
#
|
21
|
+
# As usual, patches welcome.
|
22
|
+
#
|
23
|
+
# @api external
|
24
|
+
# @see Mock.session
|
25
|
+
# @author manveru
|
26
|
+
def render_full(path, query = {})
|
27
|
+
uri = URI(path.to_s)
|
28
|
+
uri.query = Rack::Utils.build_query(query)
|
29
|
+
|
30
|
+
if cookie = request.env['HTTP_COOKIE']
|
31
|
+
Mock.session do |mock|
|
32
|
+
mock.cookie = cookie
|
33
|
+
return mock.get(uri.to_s).body
|
34
|
+
end
|
35
|
+
else
|
36
|
+
Mock.get(uri.to_s).body
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Renders an action without any layout.
|
41
|
+
# @api external
|
42
|
+
# @see render_custom
|
43
|
+
# @author manveru
|
44
|
+
def render_partial(action_name, variables = {})
|
45
|
+
render_custom(action_name, variables) do |action|
|
46
|
+
action.layout = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Renders an action view, doesn't execute any methods and won't wrap it
|
51
|
+
# into a layout.
|
52
|
+
#
|
53
|
+
# @api external
|
54
|
+
# @see render_custom
|
55
|
+
# @author manveru
|
56
|
+
def render_view(action_name, variables = {})
|
57
|
+
render_custom(action_name, variables) do |action|
|
58
|
+
action.layout = nil
|
59
|
+
action.method = nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def render_custom(action_name, variables = {})
|
64
|
+
action = resolve(action_name.to_s)
|
65
|
+
|
66
|
+
action.sync_variables(self.action)
|
67
|
+
action.instance = action.node.new
|
68
|
+
action.variables = action.variables.merge(variables)
|
69
|
+
|
70
|
+
yield(action) if block_given?
|
71
|
+
|
72
|
+
if action.valid?
|
73
|
+
action.render
|
74
|
+
else
|
75
|
+
Log.warn("Invalid action: %p" % action)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/innate/mock.rb
CHANGED
@@ -39,9 +39,8 @@ module Innate
|
|
39
39
|
hash['HTTP_COOKIE'] ||= @cookie if @cookie
|
40
40
|
response = Mock::mock(method, path, hash)
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
end
|
42
|
+
cookie = response['Set-Cookie']
|
43
|
+
@cookie = cookie if cookie
|
45
44
|
|
46
45
|
response
|
47
46
|
end
|
data/lib/innate/node.rb
CHANGED
@@ -28,7 +28,8 @@ module Innate
|
|
28
28
|
module Node
|
29
29
|
include Traited
|
30
30
|
|
31
|
-
|
31
|
+
attr_reader :method_arities, :layout_templates, :view_templates
|
32
|
+
|
32
33
|
NODE_LIST = Set.new
|
33
34
|
|
34
35
|
# These traits are inherited into ancestors, changing a trait in an
|
@@ -56,8 +57,6 @@ module Innate
|
|
56
57
|
# Upon inclusion we make ourselves comfortable.
|
57
58
|
def self.included(into)
|
58
59
|
into.__send__(:include, Helper)
|
59
|
-
into.helper(*DEFAULT_HELPERS)
|
60
|
-
|
61
60
|
into.extend(Trinity, self)
|
62
61
|
|
63
62
|
NODE_LIST << into
|
@@ -372,6 +371,7 @@ module Innate
|
|
372
371
|
end
|
373
372
|
|
374
373
|
node.update_method_arities
|
374
|
+
node.update_template_mappings
|
375
375
|
node.fill_action(action, name)
|
376
376
|
end
|
377
377
|
|
@@ -537,12 +537,10 @@ module Innate
|
|
537
537
|
@method_arities
|
538
538
|
end
|
539
539
|
|
540
|
-
attr_reader :method_arities
|
541
|
-
|
542
540
|
# Try to find the best template for the given basename and wish and respect
|
543
541
|
# aliased views.
|
544
542
|
#
|
545
|
-
# @param [#to_s]
|
543
|
+
# @param [#to_s] action_name
|
546
544
|
# @param [#to_s] wish
|
547
545
|
#
|
548
546
|
# @return [String, nil] depending whether a template could be found
|
@@ -550,11 +548,11 @@ module Innate
|
|
550
548
|
# @api external
|
551
549
|
# @see Node#to_template Node#find_aliased_view
|
552
550
|
# @author manveru
|
553
|
-
def find_view(
|
554
|
-
aliased = find_aliased_view(
|
551
|
+
def find_view(action_name, wish)
|
552
|
+
aliased = find_aliased_view(action_name, wish)
|
555
553
|
return aliased if aliased
|
556
554
|
|
557
|
-
to_view(
|
555
|
+
to_view(action_name, wish)
|
558
556
|
end
|
559
557
|
|
560
558
|
# Try to find the best template for the given basename and wish.
|
@@ -562,7 +560,7 @@ module Innate
|
|
562
560
|
# This method is mostly here for symetry with {to_layout} and to allow you
|
563
561
|
# overriding the template lookup easily.
|
564
562
|
#
|
565
|
-
# @param [#to_s]
|
563
|
+
# @param [#to_s] action_name
|
566
564
|
# @param [#to_s] wish
|
567
565
|
#
|
568
566
|
# @return [String, nil] depending whether a template could be found
|
@@ -571,9 +569,9 @@ module Innate
|
|
571
569
|
# @see {Node#find_view} {Node#to_template} {Node#root_mappings}
|
572
570
|
# {Node#view_mappings} {Node#to_template}
|
573
571
|
# @author manveru
|
574
|
-
def to_view(
|
575
|
-
|
576
|
-
|
572
|
+
def to_view(action_name, wish)
|
573
|
+
return unless files = view_templates[wish.to_s]
|
574
|
+
files[action_name.to_s]
|
577
575
|
end
|
578
576
|
|
579
577
|
# Aliasing one view from another.
|
@@ -611,9 +609,9 @@ module Innate
|
|
611
609
|
trait[:alias_view][to.to_s] = node ? [from.to_s, node] : from.to_s
|
612
610
|
end
|
613
611
|
|
614
|
-
# Resolve one level of aliasing for the given +
|
612
|
+
# Resolve one level of aliasing for the given +action_name+ and +wish+.
|
615
613
|
#
|
616
|
-
# @param [String]
|
614
|
+
# @param [String] action_name
|
617
615
|
# @param [String] wish
|
618
616
|
#
|
619
617
|
# @return [nil, String] the absolute path to the aliased template or nil
|
@@ -621,18 +619,21 @@ module Innate
|
|
621
619
|
# @api internal
|
622
620
|
# @see Node::alias_view Node::find_view
|
623
621
|
# @author manveru
|
624
|
-
def find_aliased_view(
|
625
|
-
|
622
|
+
def find_aliased_view(action_name, wish)
|
623
|
+
aliased_name, aliased_node = ancestral_trait[:alias_view][action_name]
|
624
|
+
return unless aliased_name
|
625
|
+
|
626
626
|
aliased_node ||= self
|
627
|
-
aliased_node.
|
627
|
+
aliased_node.update_view_mappings
|
628
|
+
aliased_node.find_view(aliased_name, wish)
|
628
629
|
end
|
629
630
|
|
630
|
-
# Find the best matching
|
631
|
+
# Find the best matching action_name for the layout, if any.
|
631
632
|
#
|
632
633
|
# This is mostly an abstract method that you might find handy if you want
|
633
634
|
# to do vastly different layout lookup.
|
634
635
|
#
|
635
|
-
# @param [String]
|
636
|
+
# @param [String] action_name
|
636
637
|
# @param [String] wish
|
637
638
|
#
|
638
639
|
# @return [nil, String] the absolute path to the template or nil
|
@@ -640,9 +641,9 @@ module Innate
|
|
640
641
|
# @api external
|
641
642
|
# @see {Node#to_template} {Node#root_mappings} {Node#layout_mappings}
|
642
643
|
# @author manveru
|
643
|
-
def to_layout(
|
644
|
-
|
645
|
-
|
644
|
+
def to_layout(action_name, wish)
|
645
|
+
return unless files = layout_templates[wish.to_s]
|
646
|
+
files[action_name.to_s]
|
646
647
|
end
|
647
648
|
|
648
649
|
# Define a layout to use on this Node.
|
@@ -727,11 +728,11 @@ module Innate
|
|
727
728
|
result = nil
|
728
729
|
|
729
730
|
atoms.size.downto(0) do |len|
|
730
|
-
|
731
|
+
action_name = atoms[0...len].join('__')
|
731
732
|
params = atoms[len..-1]
|
732
|
-
|
733
|
+
action_name = 'index' if action_name.empty? and params != ['index']
|
733
734
|
|
734
|
-
return result if result = yield(
|
735
|
+
return result if result = yield(action_name, params)
|
735
736
|
end
|
736
737
|
|
737
738
|
return nil
|
@@ -781,31 +782,59 @@ module Innate
|
|
781
782
|
# Node#path_glob Node#ext_glob
|
782
783
|
# @author manveru
|
783
784
|
def to_template(path, wish)
|
784
|
-
|
785
|
-
|
786
|
-
found = Dir[glob].uniq
|
785
|
+
to_view(path, wish) || to_layout(path, wish)
|
786
|
+
end
|
787
787
|
|
788
|
-
|
789
|
-
|
788
|
+
def update_template_mappings
|
789
|
+
update_view_mappings
|
790
|
+
update_layout_mappings
|
791
|
+
end
|
790
792
|
|
791
|
-
|
793
|
+
def update_view_mappings
|
794
|
+
paths = possible_paths_for(view_mappings)
|
795
|
+
@view_templates = update_mapping_shared(paths)
|
792
796
|
end
|
793
797
|
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
798
|
+
def update_layout_mappings
|
799
|
+
paths = possible_paths_for(layout_mappings)
|
800
|
+
@layout_templates = update_mapping_shared(paths)
|
801
|
+
end
|
802
|
+
|
803
|
+
def update_mapping_shared(paths)
|
804
|
+
mapping = {}
|
805
|
+
|
806
|
+
provides.each do |wish_key, engine|
|
807
|
+
wish = wish_key[/(.*)_handler/, 1]
|
808
|
+
ext_glob = ext_glob(wish)
|
809
|
+
|
810
|
+
paths.reverse_each do |path|
|
811
|
+
::Dir.glob(::File.join(path, "/**/*.#{ext_glob}")) do |file|
|
812
|
+
case file.sub(path, '').gsub('/', '__')
|
813
|
+
when /^(.*)\.(.*)\.(.*)$/
|
814
|
+
action_name, wish_ext, engine_ext = $1, $2, $3
|
815
|
+
when /^(.*)\.(.*)$/
|
816
|
+
action_name, wish_ext, engine_ext = $1, 'html', $2
|
817
|
+
when /.*/
|
818
|
+
p $1
|
819
|
+
end
|
820
|
+
|
821
|
+
mapping[wish_ext] ||= {}
|
822
|
+
mapping[wish_ext][action_name] = file
|
823
|
+
end
|
824
|
+
end
|
825
|
+
end
|
826
|
+
|
827
|
+
return mapping
|
828
|
+
end
|
829
|
+
|
830
|
+
def possible_paths_for(mappings)
|
831
|
+
root_mappings.map{|root_mapping|
|
832
|
+
mappings.first.map{|outer_mapping|
|
833
|
+
mappings.last.map{|inner_mapping|
|
834
|
+
File.join(root_mapping, outer_mapping, inner_mapping, '/')
|
835
|
+
}
|
836
|
+
}
|
837
|
+
}.flatten
|
809
838
|
end
|
810
839
|
|
811
840
|
# Produce a glob that can be processed by Dir::[] matching the extensions
|
@@ -842,7 +871,7 @@ module Innate
|
|
842
871
|
# @api external
|
843
872
|
# @author manveru
|
844
873
|
def root_mappings
|
845
|
-
[*options.roots].
|
874
|
+
[*options.roots].flatten
|
846
875
|
end
|
847
876
|
|
848
877
|
# Set the paths for lookup below the Innate.options.views paths.
|
@@ -873,7 +902,7 @@ module Innate
|
|
873
902
|
paths = [*ancestral_trait[:views]]
|
874
903
|
paths = [mapping] if paths.empty?
|
875
904
|
|
876
|
-
[*options.views]
|
905
|
+
[[*options.views].flatten, [*paths].flatten]
|
877
906
|
end
|
878
907
|
|
879
908
|
# Set the paths for lookup below the Innate.options.layouts paths.
|
@@ -904,7 +933,7 @@ module Innate
|
|
904
933
|
paths = [*ancestral_trait[:layouts]]
|
905
934
|
paths = [mapping] if paths.empty?
|
906
935
|
|
907
|
-
[*options.layouts]
|
936
|
+
[[*options.layouts].flatten, [*paths].flatten]
|
908
937
|
end
|
909
938
|
|
910
939
|
def options
|
data/lib/innate/options.rb
CHANGED
@@ -2,7 +2,7 @@ module Innate
|
|
2
2
|
# this has to be run after a couple of other files have been required
|
3
3
|
|
4
4
|
options.dsl do
|
5
|
-
o "
|
5
|
+
o "Innate::start will not start an adapter if true",
|
6
6
|
:started, false
|
7
7
|
|
8
8
|
o "Will send ::setup to each element during Innate::start",
|
data/lib/innate/request.rb
CHANGED
@@ -71,7 +71,7 @@ module Innate
|
|
71
71
|
# Both +value+ and the elements of +keys+ will be turned into String by #to_s.
|
72
72
|
def [](value, *keys)
|
73
73
|
return super(value) if keys.empty?
|
74
|
-
[value, *keys].map{|
|
74
|
+
[value, *keys].map{|key| super(key) }
|
75
75
|
end
|
76
76
|
|
77
77
|
# the full request URI provided by Rack::Request
|
@@ -94,8 +94,8 @@ module Innate
|
|
94
94
|
# # => {'name' => 'jason', 'job' => 'lumberjack'}
|
95
95
|
|
96
96
|
def subset(*keys)
|
97
|
-
keys = keys.map{|
|
98
|
-
params.reject{|
|
97
|
+
keys = keys.map{|key| key.to_s }
|
98
|
+
params.reject{|key, value| not keys.include?(key) }
|
99
99
|
end
|
100
100
|
|
101
101
|
# Try to figure out the domain we are running on, this might work for some
|
@@ -137,25 +137,5 @@ module Innate
|
|
137
137
|
rescue ArgumentError => ex
|
138
138
|
raise ArgumentError, ex unless ex.message == 'invalid address'
|
139
139
|
end
|
140
|
-
|
141
|
-
REQUEST_STRING_FORMAT = "#<%s params=%p cookies=%p env=%p>"
|
142
|
-
|
143
|
-
def to_s
|
144
|
-
REQUEST_STRING_FORMAT % [self.class, params, cookies, http_variables]
|
145
|
-
end
|
146
|
-
alias inspect to_s
|
147
|
-
|
148
|
-
# Pretty prints current action with parameters, cookies and enviroment
|
149
|
-
# variables.
|
150
|
-
def pretty_print(pp)
|
151
|
-
pp.object_group(self){
|
152
|
-
group = { 'params' => params, 'cookies' => cookies, 'env' => http_vars }
|
153
|
-
group.each do |name, hash|
|
154
|
-
pp.breakable
|
155
|
-
pp.text " @#{name}="
|
156
|
-
pp.nest(name.size + 3){ pp.pp_hash(hash) }
|
157
|
-
end
|
158
|
-
}
|
159
|
-
end
|
160
140
|
end
|
161
141
|
end
|