trellis 0.0.4 → 0.0.5

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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ nbproject
2
+ .DS_Store
3
+ Thumbs.db
4
+ **/.svn
5
+ website
data/History.txt CHANGED
@@ -1,6 +1,23 @@
1
- == 0.0.2 2009-09-19
1
+ == 0.0.5
2
+ * 2 major enhancements:
3
+ * template can now use erb (erubis using Processing Instructions (PI))
4
+ * added check for nil Rack::Session when using Cookie Store
5
+
6
+ == 0.0.4
7
+ * 1 major enhancement:
8
+ * tests for Renderer
9
+ * more routing tests
10
+ * request query params now available to page as instance variables
11
+ * cleaned up dependencies
2
12
 
3
- * 3 major enhancements:
13
+ == 0.0.3
14
+ * 1 major enhancement:
15
+ * stand-in pages
16
+
17
+ == 0.0.2 2009-09-19
18
+ * 5 major enhancements:
19
+ * code reloading
20
+ * template reloading
4
21
  * event subsystem revamped
5
22
  * custom routing
6
23
  * more tests!
@@ -8,4 +25,4 @@
8
25
  == 0.0.1 2009-08-29
9
26
 
10
27
  * 1 major enhancement:
11
- * Initial release
28
+ * initial release
data/Manifest.txt CHANGED
@@ -1,7 +1,9 @@
1
+ .gitignore
1
2
  History.txt
2
3
  License.txt
3
4
  Manifest.txt
4
5
  README
6
+ README.txt
5
7
  Rakefile
6
8
  config/hoe.rb
7
9
  config/requirements.rb
@@ -109,6 +111,7 @@ test/component_spec.rb
109
111
  test/core_extensions_spec.rb
110
112
  test/default_router_spec.rb
111
113
  test/fixtures/application_spec_applications.rb
114
+ test/fixtures/component_spec_components.rb
112
115
  test/page_spec.rb
113
116
  test/renderer_spec.rb
114
117
  test/router_spec.rb
data/README.txt ADDED
@@ -0,0 +1,156 @@
1
+ = Project: Trellis
2
+
3
+ Trellis is a component-based Web Application Framework written in Ruby.
4
+ Its main goal is to bring component-driven development to the micro-framework world.
5
+ The framework aims to be a zero-configuration framework.
6
+
7
+ It draws inspiration from:
8
+
9
+ Ruby Web Frameworks
10
+ ===================
11
+ * Rails
12
+ * Camping
13
+ * Merb
14
+ * Iowa
15
+ * Sinatra
16
+
17
+ Java Web Frameworks
18
+ ===================
19
+ * Tapesty
20
+ * Wicket
21
+ * The good parts of JSF (components)
22
+
23
+ Others
24
+ ======
25
+ * Seaside
26
+
27
+ == Goals
28
+ Accomplished goals are marked with a (*)
29
+ - * Pure HTML templates or in-line template creation with Markaby or HAML
30
+ - * To abstract away the request-response nature of web development and replace
31
+ with events and listeners
32
+ - * Reusable, extensible components including invisible components (behavior
33
+ providers), tags (stateless components) or stateful components
34
+ - Easy component composition and markup inheritance
35
+ - * Multi-threading support
36
+ - * Heavy CoC :-) (Convention Over Configuration) ala Rails
37
+ - * No static code generation, no generators, just a Ruby file!
38
+ - * Component Libraries as Gems
39
+ - * Solid Ajax support attached to the event model using a single* massively tested
40
+ Ajax framework/toolkit such as JQuery
41
+ - Skinnable components a la DotNet. That is the ability to apply a theme to a
42
+ page and cascade that to the contained components
43
+ - Support for continuations in a componentized fashion (maybe)
44
+ - CRUD behaviours for Pages/Components and using Datamapper under the covers
45
+ - Web-based debugging and administration of the application similar to what
46
+ Seaside provides
47
+
48
+ == Development Goals (To-do's)
49
+
50
+ - Keep the core framework in a single file
51
+ - Keep the core components in another file
52
+ - I have not done anything about exception handling (didn't wanted to litter the
53
+ code base). Currently I'm always sending an HTTP 200 back or I'm just letting
54
+ the app blow chuncks and showing rack's exception page
55
+ - Radius usage is really entrenched in the current component implementation need
56
+ to clean it up
57
+ - Currently Trellis uses the Mongrel Rack Adapter. In the near future the
58
+ particular web server would be configurable (one of the reasons to use Rack)
59
+
60
+ == Classes
61
+
62
+ Trellis::Application:: Base case for all Trellis applications
63
+ Trellis::Page:: Base class for all application Pages
64
+ Trellis::Renderer:: Renders XML/XHTML tags in the markup using Radius
65
+ Trellis::Component:: Base class for all Trellis components (work in progress)
66
+ Trellis::DefaultRouter:: Encapsulates the default routing logic
67
+
68
+ == <b>Notes</b>::
69
+
70
+ * Event model is pretty shallow right now. Basically events are just
71
+ a convention of how the URLs are interpreted which results on a page method
72
+ being invoked. A given URL contains information about the target page, event,
73
+ source of the event and possible context values.This information is used to
74
+ map to a single method in the page.
75
+ * Navigation is a la Tapestry; Page methods can return the instance of a
76
+ injected Page or they can return self in which case the same page is
77
+ re-rendered.
78
+ * Component can register their event handlers with the page. The page wraps the
79
+ event handlers of the contained components and dispatches the events to the
80
+ component instance.
81
+ * Currently the Application is a single object, the multi-threading (which I had
82
+ nothing to do with is provided by Rack) happens in the request dispatching.
83
+ * Trellis is not a managed framework like Tapestry, in that sense it is more like
84
+ Wicket. Pages instances are just created when needed, there is no pooling,
85
+ or any of the complexity involved in activating/passivating objects to a pool.
86
+
87
+ == Installation
88
+
89
+ * <tt>gem install trellis</tt>
90
+
91
+ A Trellis application consists of the Application class; a descendant of
92
+ Trellis::Application and one or more pages; descendants of Trellis::Page. The
93
+ Application at a minimum needs to declare the starting or home page:
94
+
95
+ module Hello
96
+ class HelloWorld < Trellis::Application
97
+ home :home
98
+ end
99
+
100
+ class Home < Trellis::Page
101
+ template do html { body { h1 "Hello World!" }} end
102
+ end
103
+ end
104
+
105
+ To run the above application simply add the line:
106
+
107
+ Hello::HelloWorld.new.start
108
+
109
+ That will start the application on Mongrel running on port 3000 by default. To
110
+ run on any other port pass the port number to the start method like:
111
+
112
+ Hello::HelloWorld.new.start 8282
113
+
114
+ == Required Gems
115
+
116
+ rack => http://rack.rubyforge.org
117
+ mongrel => http://mongrel.rubyforge.org
118
+ radius => http://radius.rubyforge.org
119
+ builder => http://builder.rubyforge.org
120
+ paginator => http://paginator.rubyforge.org
121
+ hpricot => http://code.whytheluckystiff.net/hpricot
122
+ extensions => http://extensions.rubyforge.org
123
+ haml => http://haml.hamptoncatlin.com
124
+ markaby => http://code.whytheluckystiff.net/markaby
125
+
126
+ == LICENSE:
127
+
128
+ (The MIT License)
129
+
130
+ Copyright &169;2001-2009 Integrallis Software, LLC.
131
+
132
+ Permission is hereby granted, free of charge, to any person obtaining
133
+ a copy of this software and associated documentation files (the
134
+ 'Software'), to deal in the Software without restriction, including
135
+ without limitation the rights to use, copy, modify, merge, publish,
136
+ distribute, sublicense, and/or sell copies of the Software, and to
137
+ permit persons to whom the Software is furnished to do so, subject to
138
+ the following conditions:
139
+
140
+ The above copyright notice and this permission notice shall be
141
+ included in all copies or substantial portions of the Software.
142
+
143
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
144
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
145
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
146
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
147
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
148
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
149
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
150
+
151
+ == Contact
152
+
153
+ Author:: Brian Sam-Bodden
154
+ Email:: bsbodden@integrallis.com
155
+ Home Page:: http://integrallis.com
156
+ License:: MIT Licence (http://www.opensource.org/licenses/mit-license.html)
data/Rakefile CHANGED
@@ -2,3 +2,6 @@ require 'config/requirements'
2
2
  require 'config/hoe' # setup Hoe + all gem configuration
3
3
 
4
4
  Dir['tasks/**/*.rake'].each { |rake| load rake }
5
+
6
+ task :default => :spec
7
+
data/config/hoe.rb CHANGED
@@ -9,20 +9,24 @@ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
9
  DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
10
  EXTRA_DEPENDENCIES = [
11
11
  ['paginator', '>= 1.1.1'],
12
- ['rack', '>= 0.4.0'],
13
- ['radius', '>= 0.5.1'],
12
+ ['rack', '>= 1.0.1'],
13
+ ['radius', '>= 0.6.1'],
14
14
  ['builder', '>= 2.1.2'],
15
15
  ['hpricot', '>= 0.6.0'],
16
16
  ['extensions', '>= 0.6.0'],
17
- ['haml', '>= 2.0.3'],
18
- ['RedCloth', '>= 4.0.3'],
19
- ['BlueCloth', '>= 1.0.0'],
17
+ ['haml', '>= 2.2.9'],
18
+ ['RedCloth', '>= 4.2.2'],
19
+ ['bluecloth', '>= 2.0.5'],
20
20
  ['markaby', '>= 0.5'],
21
- ['log4r', '>= 1.0.5'],
22
- ['dm-core', '>= 0.9.5'],
23
- ['dm-validations', '>= 0.9.5'],
24
- ['dm-timestamps', '>= 0.9.5'],
25
- ['english', '>= 0.2.0']
21
+ ['log4r', '>= 1.1.2'],
22
+ ['facets', '>= 2.7.0'],
23
+ ['directory_watcher', '>= 1.2.0'],
24
+ ['rack-cache', '>= 0.5.2'],
25
+ ['rack-contrib', '>= 0.9.2'],
26
+ ['rack-test', '>= 0.5.0'],
27
+ ['erubis', '>= 2.6.5'],
28
+ ['rspec', '>= 1.2.9'],
29
+ ['newgem', '>= 1.5.2']
26
30
  ] # An array of rubygem dependencies [name, version]
27
31
 
28
32
  @config_file = "~/.rubyforge/user-config.yml"
@@ -62,18 +66,19 @@ end
62
66
 
63
67
  # Generate all the Rake tasks
64
68
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
65
- $hoe = Hoe.new(GEM_NAME, VERS) do |p|
66
- p.developer(AUTHOR, EMAIL)
67
- p.description = DESCRIPTION
68
- p.summary = DESCRIPTION
69
- p.url = HOMEPATH
70
- p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
71
- p.test_globs = ["test/**/test_*.rb"]
72
- p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
69
+ $hoe = Hoe.spec GEM_NAME do
70
+ self.version = VERS
71
+ self.developer(AUTHOR, EMAIL)
72
+ self.description = DESCRIPTION
73
+ self.summary = DESCRIPTION
74
+ self.url = HOMEPATH
75
+ self.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
76
+ self.test_globs = ["test/**/test_*.rb"]
77
+ self.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
73
78
 
74
79
  # == Optional
75
- p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
76
- p.extra_deps = EXTRA_DEPENDENCIES
80
+ self.changes = paragraphs_of("History.txt", 0..1).join("\n\n")
81
+ self.extra_deps = EXTRA_DEPENDENCIES
77
82
  end
78
83
 
79
84
  CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
@@ -37,9 +37,9 @@ require 'haml'
37
37
  require 'markaby'
38
38
  require 'redcloth'
39
39
  require 'bluecloth'
40
- require 'english/inflect'
41
40
  require 'facets'
42
41
  require 'directory_watcher'
42
+ require 'erubis'
43
43
 
44
44
  module Trellis
45
45
 
@@ -116,7 +116,7 @@ module Trellis
116
116
 
117
117
  Application.logger.debug "request received with url_root of #{request.script_name}" if request.script_name
118
118
 
119
- session = env["rack.session"]
119
+ session = env['rack.session'] ||= {}
120
120
 
121
121
  router = find_router_for(request)
122
122
  route = router.route(request)
@@ -239,6 +239,7 @@ module Trellis
239
239
  else
240
240
  {}
241
241
  end
242
+ params << request.params
242
243
  params.each_pair { |name, value| page.instance_variable_set("@#{name}".to_sym, value) }
243
244
  end
244
245
  end
@@ -315,7 +316,7 @@ module Trellis
315
316
  # components in the same page or other pages
316
317
  class Page
317
318
 
318
- TEMPLATE_FORMATS = [:html, :xhtml, :haml, :textile, :markdown]
319
+ TEMPLATE_FORMATS = [:html, :xhtml, :haml, :textile, :markdown, :eruby]
319
320
 
320
321
  @@subclasses = Hash.new
321
322
  @@template_registry = Hash.new
@@ -342,19 +343,19 @@ module Trellis
342
343
  end
343
344
 
344
345
  def self.template(body = nil, options = nil, &block)
345
- format = options[:format] if options
346
+ @format = (options[:format] if options) || :html
346
347
  if block_given?
347
348
  mab = Markaby::Builder.new({}, self, &block)
348
349
  html = mab.to_s
349
350
  else
350
- case format
351
+ case @format
351
352
  when :haml
352
353
  html = Haml::Engine.new(body).render
353
354
  when :textile
354
355
  html = RedCloth.new(body).to_html
355
356
  when :markdown
356
- html = BlueCloth.new(body).to_html
357
- else # assume the body is (x)html
357
+ html = "<html><body>#{BlueCloth.new(body).to_html}</body></html>"
358
+ else # assume the body is (x)html, also eruby is treated as (x)html at this point
358
359
  html = body
359
360
  end
360
361
  end
@@ -371,6 +372,10 @@ module Trellis
371
372
  end
372
373
  @template
373
374
  end
375
+
376
+ def self.format
377
+ @format
378
+ end
374
379
 
375
380
  def self.pages(*syms)
376
381
  @pages = @pages | syms
@@ -408,7 +413,7 @@ module Trellis
408
413
  unless value
409
414
  method_result = send method.to_sym
410
415
  else
411
- method_result = send method.to_sym, value
416
+ method_result = send method.to_sym, Rack::Utils.unescape(value)
412
417
  end
413
418
 
414
419
  # determine navigation flow based on the return value of the method call
@@ -614,6 +619,8 @@ module Trellis
614
619
  def initialize(page)
615
620
  @page = page
616
621
  @context = Context.new
622
+ # context for erubis templates
623
+ @eruby_context = {} if @page.class.format == :eruby
617
624
 
618
625
  # add all instance variables in the page as values accesible from the tags
619
626
  page.instance_variables.each do |var|
@@ -621,17 +628,19 @@ module Trellis
621
628
  unless value.kind_of?(Trellis::Page)
622
629
  sym = "#{var}=".split('@').last.to_sym
623
630
  @context.globals.send(sym, value)
631
+ @eruby_context["#{var}".split('@').last] = value if @eruby_context
624
632
  end
625
633
  end
626
634
 
627
635
  # add other useful values to the tag context
628
636
  @context.globals.send(:page_name=, page.class.to_s)
637
+ @eruby_context[:page_name] = page.class.to_s if @eruby_context
629
638
 
630
639
  #TODO add public page methods to the context
631
640
 
632
-
633
641
  # add the page to the context too
634
642
  @context.globals.page = page
643
+ @eruby_context[:page] = page if @eruby_context
635
644
 
636
645
  # register the components contained in the page with the renderer's context
637
646
  page.class.components.each do |component|
@@ -642,7 +651,13 @@ module Trellis
642
651
  end
643
652
 
644
653
  def render
645
- @parser.parse(@page.class.parsed_template.to_html)
654
+ unless @page.class.format == :eruby
655
+ @parser.parse(@page.class.parsed_template.to_html)
656
+ else
657
+ puts "eruby context is #{@eruby_context}"
658
+ preprocessed = Erubis::PI::Eruby.new(@page.class.parsed_template.to_html, :trim => false).evaluate(@eruby_context)
659
+ @parser.parse(preprocessed)
660
+ end
646
661
  end
647
662
 
648
663
  end # renderer
data/lib/trellis/utils.rb CHANGED
@@ -24,12 +24,6 @@
24
24
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
25
  #++
26
26
 
27
- module Kernel
28
- def with( object, &block )
29
- object.instance_eval(&block); object
30
- end
31
- end
32
-
33
27
  class Object #:nodoc:
34
28
  def meta_def(m,&b) #:nodoc:
35
29
  metaclass.send(:define_method,m,&b)
@@ -99,6 +93,30 @@ class Class #:nodoc:
99
93
  end
100
94
 
101
95
  class String #:nodoc:
96
+
97
+ PLURALS = [['(quiz)$', '\1zes'],['(ox)$', '\1en'],['([m|l])ouse$', '\1ice'],['(matr|vert|ind)ix|ex$', '\1ices'],
98
+ ['(x|ch|ss|sh)$', '\1es'],['([^aeiouy]|qu)ies$', '\1y'],['([^aeiouy]|q)y$$', '\1ies'],['(hive)$', '\1s'],
99
+ ['(?:[^f]fe|([lr])f)$', '\1\2ves'],['(sis)$', 'ses'],['([ti])um$', '\1a'],['(buffal|tomat)o$', '\1oes'],['(bu)s$', '\1es'],
100
+ ['(alias|status)$', '\1es'],['(octop|vir)us$', '\1i'],['(ax|test)is$', '\1es'],['s$', 's'],['$', 's']]
101
+ SINGULARS =[['(quiz)zes$', '\1'],['(matr)ices$', '\1ix'],['(vert|ind)ices$', '\1ex'],['^(ox)en$', '\1'],['(alias|status)es$', '\1'],
102
+ ['(octop|vir)i$', '\1us'],['(cris|ax|test)es$', '\1is'],['(shoe)s$', '\1'],['[o]es$', '\1'],['[bus]es$', '\1'],['([m|l])ice$', '\1ouse'],
103
+ ['(x|ch|ss|sh)es$', '\1'],['(m)ovies$', '\1ovie'],['[s]eries$', '\1eries'],['([^aeiouy]|qu)ies$', '\1y'],['[lr]ves$', '\1f'],
104
+ ['(tive)s$', '\1'],['(hive]s$', '\1'],['([^f]]ves$', '\1fe'],['(^analy)ses$', '\1sis'],
105
+ ['([a]naly|[b]a|[d]iagno|[p]arenthe|[p]rogno|[s]ynop|[t]he)ses$', '\1\2sis'],['([ti])a$', '\1um'],['(news)$', '\1ews']]
106
+
107
+ def singular()
108
+ SINGULARS.each { |match_exp, replacement_exp| return gsub(Regexp.compile(match_exp), replacement_exp) unless match(Regexp.compile(match_exp)).nil?}
109
+ end
110
+
111
+ def plural()
112
+ PLURALS.each { |match_exp, replacement_exp| return gsub(Regexp.compile(match_exp), replacement_exp) unless match(Regexp.compile(match_exp)).nil? }
113
+ end
114
+
115
+ def plural?
116
+ PLURALS.each {|match_exp, replacement_exp| return true if match(Regexp.compile(match_exp))}
117
+ false
118
+ end
119
+
102
120
  def blank?
103
121
  self !~ /\S/
104
122
  end
@@ -28,7 +28,7 @@ module Trellis
28
28
  module VERSION #:nodoc:
29
29
  MAJOR = 0
30
30
  MINOR = 0
31
- TINY = 4
31
+ TINY = 5
32
32
 
33
33
  STRING = [MAJOR, MINOR, TINY].join('.')
34
34
  end
@@ -89,7 +89,7 @@ describe Trellis::Application, " requesting a route" do
89
89
  response.body.should == '<html><body>goodbye/cruel/world</body></html>'
90
90
  end
91
91
 
92
- it "should supports mixing multiple splat" do
92
+ it "should supports mixing multiple splats" do
93
93
  response = @request.get('/splats/bar/foo/bling/baz/boom')
94
94
  response.body.should == '<html><body>barblingbaz/boom</body></html>'
95
95
 
@@ -101,4 +101,19 @@ describe Trellis::Application, " requesting a route" do
101
101
  response = @request.get('/mixed/afoo/bar/baz')
102
102
  response.body.should == '<html><body>bar/baz-afoo</body></html>'
103
103
  end
104
+
105
+ it "should merge named params and query string params" do
106
+ response_mr_bean = @request.get("/hello/Bean?salutation=Mr.%20")
107
+ response_mr_bean.body.should == "<html><body><h2>Hello</h2>Mr. Bean</body></html>"
108
+ end
109
+
110
+ it "should match a dot ('.') as part of a named param" do
111
+ response = @request.get("/foobar/user@example.com/thebar")
112
+ response.body.should == "<html><body>user@example.com-thebar</body></html>"
113
+ end
114
+
115
+ it "should match a literal dot ('.') outside of named params" do
116
+ response = @request.get("/downloads/logo.gif")
117
+ response.body.should == "<html><body>logo-gif</body></html>"
118
+ end
104
119
  end
@@ -22,6 +22,10 @@ module TestApp
22
22
  def on_event3
23
23
  @other
24
24
  end
25
+
26
+ def on_event4(value)
27
+ "the value is #{value}"
28
+ end
25
29
  end
26
30
 
27
31
  class Other < Trellis::Page
@@ -61,7 +65,7 @@ module TestApp
61
65
  html {
62
66
  body {
63
67
  h2 "Hello"
64
- text %[<trellis:value name="name"/>]
68
+ text %[<trellis:value name="salutation"/><trellis:value name="name"/>]
65
69
  }
66
70
  }
67
71
  end
@@ -136,4 +140,79 @@ module TestApp
136
140
  end
137
141
  end
138
142
 
143
+ class RoutedWithTwoParams < Trellis::Page
144
+ route '/foobar/:foo/:bar'
145
+
146
+ template do
147
+ html {
148
+ body {
149
+ text %[<trellis:value name="foo"/>]
150
+ text '-'
151
+ text %[<trellis:value name="bar"/>]
152
+ }
153
+ }
154
+ end
155
+ end
156
+
157
+ class RoutedWithImplicitDot < Trellis::Page
158
+ route '/downloads/:file.:ext'
159
+
160
+ template do
161
+ html {
162
+ body {
163
+ text %[<trellis:value name="file"/>]
164
+ text '-'
165
+ text %[<trellis:value name="ext"/>]
166
+ }
167
+ }
168
+ end
169
+ end
170
+
171
+ class SamplePage < Trellis::Page
172
+ attr_accessor :value
173
+ template do html { body { text %[<trellis:value name="value"/>] }} end
174
+ end
175
+
176
+ class AnotherSamplePage < Trellis::Page
177
+ template do html { body { text %[<trellis:value name="page_name"/>] }} end
178
+ end
179
+
180
+ class HamlPage < Trellis::Page
181
+ template %[!!! XML
182
+ !!! Strict
183
+ %html{ :xmlns => "http://www.w3.org/1999/xhtml" }
184
+ %head
185
+ %meta{ :content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type" }
186
+ %title
187
+ This is a HAML page
188
+ %body
189
+ %h1
190
+ Page Title
191
+ %p
192
+ HAML rocks!], :format => :haml
193
+ end
194
+
195
+ class TextilePage < Trellis::Page
196
+ template %[A *simple* example.], :format => :textile
197
+ end
198
+
199
+ class MarkDownPage < Trellis::Page
200
+ template "# This is the Title\n## This is the SubTitle\nThis is some text", :format => :markdown
201
+ end
202
+
203
+ class HTMLPage < Trellis::Page
204
+ template "<html><body><h1>This is just HTML</h1></body></html>"
205
+ end
206
+
207
+ class ERubyPage < Trellis::Page
208
+ attr_reader :list
209
+
210
+ def initialize
211
+ self
212
+ @list = ["Hey", "bud", "let's", "party!"]
213
+ end
214
+
215
+ template %[<html><body><ul><?rb for item in @list ?><li>@{item}@</li><?rb end ?></ul></body></html>], :format => :eruby
216
+ end
217
+
139
218
  end
@@ -0,0 +1,114 @@
1
+ module TestComponents
2
+
3
+ class SimpleComponent < Trellis::Component
4
+ tag_name "simple_component"
5
+
6
+ render do |tag|
7
+ "hello from simple component"
8
+ end
9
+ end
10
+
11
+ class Counter < Trellis::Component
12
+ is_stateful
13
+
14
+ tag_name "counter"
15
+
16
+ field :value, :persistent => true
17
+
18
+ def initialize
19
+ reset
20
+ end
21
+
22
+ render do |tag|
23
+ tid = tag.attr['tid']
24
+ page = tag.globals.page
25
+ counter = page.send("counter_#{tid}")
26
+ value = counter.value
27
+ href_add = Trellis::DefaultRouter.to_uri(:page => page.class.name,
28
+ :event => 'add',
29
+ :source => "counter_#{tid}")
30
+ href_subtract = Trellis::DefaultRouter.to_uri(:page => page.class.name,
31
+ :event => 'subtract',
32
+ :source => "counter_#{tid}")
33
+ builder = Builder::XmlMarkup.new
34
+ builder.div(:id => tid) {
35
+ builder.text!(value.to_s)
36
+ builder.a("++", :href => href_add)
37
+ builder.a("--", :href => href_subtract)
38
+ }
39
+ end
40
+
41
+ def on_add
42
+ @value = @value + 1
43
+ end
44
+
45
+ def on_subtract
46
+ @value = @value - 1
47
+ end
48
+
49
+ def reset
50
+ @value = 0
51
+ end
52
+ end
53
+
54
+ class Contributions < Trellis::Component
55
+ #tag_name "contributions"
56
+
57
+ # -----------------------
58
+ # component contributions
59
+ # -----------------------
60
+ page_contribution :style_link, "/someplace/my_styles.css"
61
+ page_contribution :script_link, "/someplace/my_script.js"
62
+ page_contribution :style, %[html { color:#555555; background-color:#303030; }], :scope => :class
63
+ page_contribution :style, %[/* just a comment */], :scope => :instance
64
+ page_contribution :script, %[alert('hello from ${tid}');], :scope => :instance
65
+ page_contribution :script, %[alert('hello just once');], :scope => :class
66
+
67
+ page_contribution(:dom) {
68
+ at("body")['class'] = 'new_class'
69
+ }
70
+
71
+ render do |tag|
72
+ "hear ye, hear ye!"
73
+ end
74
+ end
75
+
76
+ class ApplicationWithComponents < Trellis::Application
77
+ home :page_with_simple_component
78
+ end
79
+
80
+ class PageWithSimpleComponent < Trellis::Page
81
+ template do html { body { text %[<trellis:simple_component/>] }} end
82
+ end
83
+
84
+ class PageWithStatefulComponent < Trellis::Page
85
+ route '/counters'
86
+
87
+ template do
88
+ html {
89
+ body {
90
+ text %[
91
+ <trellis:counter tid="one" />
92
+ <hr/>
93
+ <trellis:counter tid="two" />
94
+ <hr/>
95
+ <trellis:counter tid="three" />
96
+ ]
97
+ }
98
+ }
99
+ end
100
+ end
101
+
102
+ class PageWithContributions < Trellis::Page
103
+ template do
104
+ html {
105
+ head {
106
+ title "counters"
107
+ }
108
+ body {
109
+ text %[<trellis:contributions tid="one"/><trellis:contributions tid="two"/>]
110
+ }
111
+ }
112
+ end
113
+ end
114
+ end
data/test/page_spec.rb CHANGED
@@ -20,11 +20,16 @@ describe Trellis::Page, " when sending an event to a page" do
20
20
  response.body.should == "just some text"
21
21
  end
22
22
 
23
- it "should redirect to the injected page as a response if the event handler returns an injected page " do
23
+ it "should redirect to the injected page as a response if the event handler returns an injected page" do
24
24
  response = @request.get("/home/events/event3")
25
25
  response.status.should be(302)
26
26
  response.headers['Location'].should == '/other'
27
27
  end
28
+
29
+ it "should be able to pass a value as the last element or the URL" do
30
+ response = @request.get("/home/events/event4/quo%20vadis")
31
+ response.body.should == "the value is quo vadis"
32
+ end
28
33
 
29
34
  it "should invoke the before_load method if provided by the page" do
30
35
  response = @request.get("/before_load")
@@ -54,3 +59,35 @@ describe Trellis::Page, " when created with a custom route" do
54
59
  end
55
60
  end
56
61
 
62
+ describe Trellis::Page, " when given a template" do
63
+ before(:each) do
64
+ @application = TestApp::MyApp.new
65
+ @request = Rack::MockRequest.new(@application)
66
+ end
67
+
68
+ it "should rendered it correctly if it is in HAML format" do
69
+ response = @request.get("/haml_page")
70
+ response.body.should == "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n <head>\n <meta content=\"text/html; charset=UTF-8\" http-equiv=\"Content-Type\" />\n <title>\n This is a HAML page\n </title>\n </head>\n <body>\n <h1>\n Page Title\n </h1>\n <p>\n HAML rocks!\n </p>\n </body>\n</html>\n"
71
+ end
72
+
73
+ it "should rendered it correctly if it is in Textile format" do
74
+ response = @request.get("/textile_page")
75
+ response.body.should == "<p>A <strong>simple</strong> example.</p>"
76
+ end
77
+
78
+ it "should rendered it correctly if it is in Markdown format" do
79
+ response = @request.get("/mark_down_page")
80
+ response.body.should == "<html><body><h1>This is the Title</h1>\n\n<h2>This is the SubTitle</h2>\n\n<p>This is some text</p></body></html>"
81
+ end
82
+
83
+ it "should rendered it correctly if it is in ERuby format" do
84
+ response = @request.get("/e_ruby_page")
85
+ response.body.should == "<html><body><ul><li>Hey</li><li>bud</li><li>let's</li><li>party!</li></ul></body></html>"
86
+ end
87
+
88
+ it "should rendered it correctly if it is in HTML format" do
89
+ response = @request.get("/html_page")
90
+ response.body.should == "<html><body><h1>This is just HTML</h1></body></html>"
91
+ end
92
+ end
93
+
@@ -1,12 +1,31 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
+ require "rack"
4
+ require_fixtures 'application_spec_applications'
5
+
3
6
  describe Trellis::Renderer do
4
- before(:each) do
5
- #@renderer = Renderer.new
7
+
8
+ it "should render a given page template" do
9
+ page = TestApp::Home.new
10
+ renderer = Trellis::Renderer.new(page)
11
+ result = renderer.render
12
+ result.should == "<html><body><h1>Hello World!</h1></body></html>"
6
13
  end
7
14
 
8
- it "should desc" do
9
- # TODO
15
+ it "should have access to page instance variables" do
16
+ page = TestApp::SamplePage.new
17
+ page.value = "chunky bacon"
18
+ renderer = Trellis::Renderer.new(page)
19
+ result = renderer.render
20
+ result.should == "<html><body>chunky bacon</body></html>"
10
21
  end
22
+
23
+ it "should have access to the page name" do
24
+ page = TestApp::AnotherSamplePage.new
25
+ renderer = Trellis::Renderer.new(page)
26
+ result = renderer.render
27
+ result.should == "<html><body>TestApp::AnotherSamplePage</body></html>"
28
+ end
29
+
11
30
  end
12
31
 
data/test/router_spec.rb CHANGED
@@ -48,5 +48,5 @@ describe Trellis::Router, " when constructed" do
48
48
  @router = Trellis::Router.new(:path => '/*')
49
49
  @router.keys.should include('splat')
50
50
  end
51
-
51
+
52
52
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trellis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Sam-Bodden
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-06 00:00:00 -07:00
12
+ date: 2009-11-08 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.4.0
33
+ version: 1.0.1
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: radius
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.5.1
43
+ version: 0.6.1
44
44
  version:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: builder
@@ -80,7 +80,7 @@ dependencies:
80
80
  requirements:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
- version: 2.0.3
83
+ version: 2.2.9
84
84
  version:
85
85
  - !ruby/object:Gem::Dependency
86
86
  name: RedCloth
@@ -90,17 +90,17 @@ dependencies:
90
90
  requirements:
91
91
  - - ">="
92
92
  - !ruby/object:Gem::Version
93
- version: 4.0.3
93
+ version: 4.2.2
94
94
  version:
95
95
  - !ruby/object:Gem::Dependency
96
- name: BlueCloth
96
+ name: bluecloth
97
97
  type: :runtime
98
98
  version_requirement:
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: 1.0.0
103
+ version: 2.0.5
104
104
  version:
105
105
  - !ruby/object:Gem::Dependency
106
106
  name: markaby
@@ -120,47 +120,87 @@ dependencies:
120
120
  requirements:
121
121
  - - ">="
122
122
  - !ruby/object:Gem::Version
123
- version: 1.0.5
123
+ version: 1.1.2
124
124
  version:
125
125
  - !ruby/object:Gem::Dependency
126
- name: dm-core
126
+ name: facets
127
127
  type: :runtime
128
128
  version_requirement:
129
129
  version_requirements: !ruby/object:Gem::Requirement
130
130
  requirements:
131
131
  - - ">="
132
132
  - !ruby/object:Gem::Version
133
- version: 0.9.5
133
+ version: 2.7.0
134
134
  version:
135
135
  - !ruby/object:Gem::Dependency
136
- name: dm-validations
136
+ name: directory_watcher
137
137
  type: :runtime
138
138
  version_requirement:
139
139
  version_requirements: !ruby/object:Gem::Requirement
140
140
  requirements:
141
141
  - - ">="
142
142
  - !ruby/object:Gem::Version
143
- version: 0.9.5
143
+ version: 1.2.0
144
144
  version:
145
145
  - !ruby/object:Gem::Dependency
146
- name: dm-timestamps
146
+ name: rack-cache
147
147
  type: :runtime
148
148
  version_requirement:
149
149
  version_requirements: !ruby/object:Gem::Requirement
150
150
  requirements:
151
151
  - - ">="
152
152
  - !ruby/object:Gem::Version
153
- version: 0.9.5
153
+ version: 0.5.2
154
154
  version:
155
155
  - !ruby/object:Gem::Dependency
156
- name: english
156
+ name: rack-contrib
157
157
  type: :runtime
158
158
  version_requirement:
159
159
  version_requirements: !ruby/object:Gem::Requirement
160
160
  requirements:
161
161
  - - ">="
162
162
  - !ruby/object:Gem::Version
163
- version: 0.2.0
163
+ version: 0.9.2
164
+ version:
165
+ - !ruby/object:Gem::Dependency
166
+ name: rack-test
167
+ type: :runtime
168
+ version_requirement:
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: 0.5.0
174
+ version:
175
+ - !ruby/object:Gem::Dependency
176
+ name: erubis
177
+ type: :runtime
178
+ version_requirement:
179
+ version_requirements: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: 2.6.5
184
+ version:
185
+ - !ruby/object:Gem::Dependency
186
+ name: rspec
187
+ type: :runtime
188
+ version_requirement:
189
+ version_requirements: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: 1.2.9
194
+ version:
195
+ - !ruby/object:Gem::Dependency
196
+ name: newgem
197
+ type: :runtime
198
+ version_requirement:
199
+ version_requirements: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: 1.5.2
164
204
  version:
165
205
  - !ruby/object:Gem::Dependency
166
206
  name: hoe
@@ -183,13 +223,16 @@ extra_rdoc_files:
183
223
  - History.txt
184
224
  - License.txt
185
225
  - Manifest.txt
226
+ - README.txt
186
227
  - examples/examples.txt
187
228
  - examples/hangman/html/resources/word_list.txt
188
229
  files:
230
+ - .gitignore
189
231
  - History.txt
190
232
  - License.txt
191
233
  - Manifest.txt
192
234
  - README
235
+ - README.txt
193
236
  - Rakefile
194
237
  - config/hoe.rb
195
238
  - config/requirements.rb
@@ -297,6 +340,7 @@ files:
297
340
  - test/core_extensions_spec.rb
298
341
  - test/default_router_spec.rb
299
342
  - test/fixtures/application_spec_applications.rb
343
+ - test/fixtures/component_spec_components.rb
300
344
  - test/page_spec.rb
301
345
  - test/renderer_spec.rb
302
346
  - test/router_spec.rb