Multi Counter
16 |The multicounter show multiple instances of a stateful component. It displays several instances of the same counter component.
17 |18 | 19 |
20 |├── .gitignore ├── History.txt ├── License.txt ├── Manifest.txt ├── README ├── README.txt ├── Rakefile ├── config ├── hoe.rb └── requirements.rb ├── examples ├── crud_components │ ├── html │ │ ├── address_view_edit.xhtml │ │ ├── addresses.xhtml │ │ ├── images │ │ │ ├── destroy.gif │ │ │ ├── edit.gif │ │ │ ├── field-error-marker.gif │ │ │ ├── sort-asc.png │ │ │ ├── sort-desc.png │ │ │ └── sortable.png │ │ └── style │ │ │ └── trellis.css │ └── source │ │ ├── crud_components.rb │ │ └── domain.rb ├── examples.txt ├── filters │ └── source │ │ └── filters.rb ├── flickr │ └── source │ │ ├── flickr.rb │ │ └── spec │ │ └── flickr_spec.rb ├── guest_book │ └── source │ │ └── guest_book.rb ├── hangman │ ├── html │ │ ├── game_over.xhtml │ │ ├── guess.xhtml │ │ ├── images │ │ │ ├── a_disabled.png │ │ │ ├── a_enabled.png │ │ │ ├── b_disabled.png │ │ │ ├── b_enabled.png │ │ │ ├── c_disabled.png │ │ │ ├── c_enabled.png │ │ │ ├── d_disabled.png │ │ │ ├── d_enabled.png │ │ │ ├── e_disabled.png │ │ │ ├── e_enabled.png │ │ │ ├── f_disabled.png │ │ │ ├── f_enabled.png │ │ │ ├── g_disabled.png │ │ │ ├── g_enabled.png │ │ │ ├── h_disabled.png │ │ │ ├── h_enabled.png │ │ │ ├── i_disabled.png │ │ │ ├── i_enabled.png │ │ │ ├── j_disabled.png │ │ │ ├── j_enabled.png │ │ │ ├── k_disabled.png │ │ │ ├── k_enabled.png │ │ │ ├── l_disabled.png │ │ │ ├── l_enabled.png │ │ │ ├── m_disabled.png │ │ │ ├── m_enabled.png │ │ │ ├── n_disabled.png │ │ │ ├── n_enabled.png │ │ │ ├── o_disabled.png │ │ │ ├── o_enabled.png │ │ │ ├── p_disabled.png │ │ │ ├── p_enabled.png │ │ │ ├── q_disabled.png │ │ │ ├── q_enabled.png │ │ │ ├── r_disabled.png │ │ │ ├── r_enabled.png │ │ │ ├── s_disabled.png │ │ │ ├── s_enabled.png │ │ │ ├── t_disabled.png │ │ │ ├── t_enabled.png │ │ │ ├── u_disabled.png │ │ │ ├── u_enabled.png │ │ │ ├── v_disabled.png │ │ │ ├── v_enabled.png │ │ │ ├── w_disabled.png │ │ │ ├── w_enabled.png │ │ │ ├── x_disabled.png │ │ │ ├── x_enabled.png │ │ │ ├── y_disabled.png │ │ │ ├── y_enabled.png │ │ │ ├── z_disabled.png │ │ │ └── z_enabled.png │ │ ├── resources │ │ │ └── word_list.txt │ │ ├── start.xhtml │ │ └── style │ │ │ └── hangman.css │ └── source │ │ └── hangman.rb ├── hilo │ ├── html │ │ ├── game_over.xhtml │ │ ├── guess.xhtml │ │ └── start.xhtml │ └── source │ │ └── hilo.rb ├── routing │ └── source │ │ └── routing.rb ├── sessions │ └── source │ │ └── sessions.rb ├── simplest │ └── source │ │ └── simplest.rb └── stateful_counters │ ├── html │ ├── counters.xhtml │ └── style │ │ └── main.css │ └── source │ └── stateful_counters.rb ├── lib ├── trellis.rb └── trellis │ ├── component_library │ ├── core_components.rb │ ├── grid.rb │ ├── jquery.rb │ └── object_editor.rb │ ├── logging.rb │ ├── trellis.rb │ ├── utils.rb │ └── version.rb ├── script ├── console ├── destroy ├── generate └── txt2html ├── setup.rb ├── tasks ├── deployment.rake ├── environment.rake ├── rspec.rake └── website.rake └── test ├── application_spec.rb ├── component_spec.rb ├── core_extensions_spec.rb ├── default_router_spec.rb ├── filters_spec.rb ├── fixtures ├── application_fixtures.rb ├── component_fixtures.rb └── filters_fixtures.rb ├── page_spec.rb ├── renderer_spec.rb ├── router_spec.rb ├── spec.opts └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject 2 | .DS_Store 3 | Thumbs.db 4 | **/.svn 5 | website 6 | coverage/* -------------------------------------------------------------------------------- /History.txt: -------------------------------------------------------------------------------- 1 | == 0.1.2 2 | * 1 major enhancement 3 | * big refactor fest #1 - removed a great deal of dup code 4 | 5 | == 0.1.1 6 | * 2 major enhancement 7 | * before, around and after filters 8 | * refactoring (clean up) of call! (rack specification) method 9 | 10 | == 0.1.0 11 | * 1 major enhancement 12 | * fix logger for rack 1.0.1 13 | 14 | == 0.0.9 15 | * 1 major enhancement: 16 | * added missing nokogiri gem from the dependencies 17 | 18 | == 0.0.8 19 | * 1 major enhancement: 20 | * implemented automatic route sorting 21 | 22 | == 0.0.7 23 | * 3 major enhancements: 24 | * ripped out rexml/hpricot replaced with nokogiri 25 | * implemented page get method to override default page rendering 26 | * added trellis namespace xmlns method for markaby 27 | * clean all examples to add trellis namespace 28 | 29 | == 0.0.6 30 | * 2 major enhancement: 31 | * added dup.call for thread safety 32 | * added ability to select Rack::Session middleware implementation 33 | between cookie, pool and memcached 34 | 35 | == 0.0.5 36 | * 2 major enhancements: 37 | * template can now use erb (erubis using Processing Instructions (PI)) 38 | * added check for nil Rack::Session when using Cookie Store 39 | 40 | == 0.0.4 41 | * 1 major enhancement: 42 | * tests for Renderer 43 | * more routing tests 44 | * request query params now available to page as instance variables 45 | * cleaned up dependencies 46 | 47 | == 0.0.3 48 | * 1 major enhancement: 49 | * stand-in pages 50 | 51 | == 0.0.2 2009-09-19 52 | * 5 major enhancements: 53 | * code reloading 54 | * template reloading 55 | * event subsystem revamped 56 | * custom routing 57 | * more tests! 58 | 59 | == 0.0.1 2009-08-29 60 | 61 | * 1 major enhancement: 62 | * initial release 63 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright &169;2001-2010 Integrallis Software, LLC. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Manifest.txt: -------------------------------------------------------------------------------- 1 | History.txt 2 | License.txt 3 | Manifest.txt 4 | README 5 | README.txt 6 | Rakefile 7 | config/hoe.rb 8 | config/requirements.rb 9 | examples/crud_components/html/address_view_edit.xhtml 10 | examples/crud_components/html/addresses.xhtml 11 | examples/crud_components/html/images/destroy.gif 12 | examples/crud_components/html/images/edit.gif 13 | examples/crud_components/html/images/field-error-marker.gif 14 | examples/crud_components/html/images/sort-asc.png 15 | examples/crud_components/html/images/sort-desc.png 16 | examples/crud_components/html/images/sortable.png 17 | examples/crud_components/html/style/trellis.css 18 | examples/crud_components/source/crud_components.rb 19 | examples/crud_components/source/domain.rb 20 | examples/examples.txt 21 | examples/filters/source/filters.rb 22 | examples/flickr/source/flickr.rb 23 | examples/guest_book/source/guest_book.rb 24 | examples/hangman/html/game_over.xhtml 25 | examples/hangman/html/guess.xhtml 26 | examples/hangman/html/images/a_disabled.png 27 | examples/hangman/html/images/a_enabled.png 28 | examples/hangman/html/images/b_disabled.png 29 | examples/hangman/html/images/b_enabled.png 30 | examples/hangman/html/images/c_disabled.png 31 | examples/hangman/html/images/c_enabled.png 32 | examples/hangman/html/images/d_disabled.png 33 | examples/hangman/html/images/d_enabled.png 34 | examples/hangman/html/images/e_disabled.png 35 | examples/hangman/html/images/e_enabled.png 36 | examples/hangman/html/images/f_disabled.png 37 | examples/hangman/html/images/f_enabled.png 38 | examples/hangman/html/images/g_disabled.png 39 | examples/hangman/html/images/g_enabled.png 40 | examples/hangman/html/images/h_disabled.png 41 | examples/hangman/html/images/h_enabled.png 42 | examples/hangman/html/images/i_disabled.png 43 | examples/hangman/html/images/i_enabled.png 44 | examples/hangman/html/images/j_disabled.png 45 | examples/hangman/html/images/j_enabled.png 46 | examples/hangman/html/images/k_disabled.png 47 | examples/hangman/html/images/k_enabled.png 48 | examples/hangman/html/images/l_disabled.png 49 | examples/hangman/html/images/l_enabled.png 50 | examples/hangman/html/images/m_disabled.png 51 | examples/hangman/html/images/m_enabled.png 52 | examples/hangman/html/images/n_disabled.png 53 | examples/hangman/html/images/n_enabled.png 54 | examples/hangman/html/images/o_disabled.png 55 | examples/hangman/html/images/o_enabled.png 56 | examples/hangman/html/images/p_disabled.png 57 | examples/hangman/html/images/p_enabled.png 58 | examples/hangman/html/images/q_disabled.png 59 | examples/hangman/html/images/q_enabled.png 60 | examples/hangman/html/images/r_disabled.png 61 | examples/hangman/html/images/r_enabled.png 62 | examples/hangman/html/images/s_disabled.png 63 | examples/hangman/html/images/s_enabled.png 64 | examples/hangman/html/images/t_disabled.png 65 | examples/hangman/html/images/t_enabled.png 66 | examples/hangman/html/images/u_disabled.png 67 | examples/hangman/html/images/u_enabled.png 68 | examples/hangman/html/images/v_disabled.png 69 | examples/hangman/html/images/v_enabled.png 70 | examples/hangman/html/images/w_disabled.png 71 | examples/hangman/html/images/w_enabled.png 72 | examples/hangman/html/images/x_disabled.png 73 | examples/hangman/html/images/x_enabled.png 74 | examples/hangman/html/images/y_disabled.png 75 | examples/hangman/html/images/y_enabled.png 76 | examples/hangman/html/images/z_disabled.png 77 | examples/hangman/html/images/z_enabled.png 78 | examples/hangman/html/resources/word_list.txt 79 | examples/hangman/html/start.xhtml 80 | examples/hangman/html/style/hangman.css 81 | examples/hangman/source/hangman.rb 82 | examples/hilo/html/game_over.xhtml 83 | examples/hilo/html/guess.xhtml 84 | examples/hilo/html/start.xhtml 85 | examples/hilo/source/hilo.rb 86 | examples/routing/source/routing.rb 87 | examples/sessions/source/sessions.rb 88 | examples/simplest/source/simplest.rb 89 | examples/stateful_counters/html/counters.xhtml 90 | examples/stateful_counters/html/style/main.css 91 | examples/stateful_counters/source/stateful_counters.rb 92 | lib/trellis.rb 93 | lib/trellis/component_library/core_components.rb 94 | lib/trellis/component_library/grid.rb 95 | lib/trellis/component_library/jquery.rb 96 | lib/trellis/component_library/object_editor.rb 97 | lib/trellis/logging.rb 98 | lib/trellis/trellis.rb 99 | lib/trellis/utils.rb 100 | lib/trellis/version.rb 101 | script/console 102 | script/destroy 103 | script/generate 104 | script/txt2html 105 | setup.rb 106 | tasks/deployment.rake 107 | tasks/environment.rake 108 | tasks/rspec.rake 109 | tasks/website.rake 110 | test/application_spec.rb 111 | test/component_spec.rb 112 | test/core_extensions_spec.rb 113 | test/default_router_spec.rb 114 | test/filters_spec.rb 115 | test/fixtures/application_fixtures.rb 116 | test/fixtures/component_fixtures.rb 117 | test/fixtures/filters_fixtures.rb 118 | test/page_spec.rb 119 | test/renderer_spec.rb 120 | test/router_spec.rb 121 | test/spec.opts 122 | test/spec_helper.rb 123 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | = Project: Trellis 2 | 3 | Trellis is a component-based Web Application Framework written in Ruby and based on Rack. 4 | Its main goal is to bring component-driven development to the micro-framework world. 5 | Trellis applications are composed of pages, pages have components, components emit events, 6 | pages and components can listen and handle events. 7 | Trellis aims to be a (close to) zero-configuration framework 8 | 9 | It draws inspiration from: 10 | 11 | Ruby Web Frameworks 12 | =================== 13 | * Rails 14 | * Camping 15 | * Merb 16 | * Iowa 17 | * Sinatra 18 | 19 | Java Web Frameworks 20 | =================== 21 | * Tapesty 22 | * Wicket 23 | 24 | Others 25 | ====== 26 | * Seaside 27 | 28 | == Goals 29 | Accomplished goals are marked with a (*) 30 | - * Pure HTML templates or in-line template creation with Markaby, HAML, erubis, Markdown and Textile 31 | - * To abstract away the request-response nature of web development and replace 32 | with events and listeners 33 | - * Reusable, extensible components including invisible components (behavior 34 | providers), tags (stateless components) or stateful components 35 | - * Easy component composition and markup inheritance 36 | - * Multi-threading support 37 | - * Heavy CoC :-) (Convention Over Configuration) ala Rails 38 | - * No static code generation, no generators, just a Ruby file! 39 | - * Component Libraries as Gems 40 | - Solid Ajax support attached to the event model using a single* massively tested 41 | Ajax framework/toolkit such as JQuery 42 | - Skinnable components a la DotNet. That is the ability to apply a theme to a 43 | page and cascade that to the contained components 44 | - Support for continuations in a componentized fashion (maybe) 45 | - CRUD behaviours for Pages/Components and using Datamapper under the covers 46 | - Web-based debugging and administration of the application similar to what 47 | Seaside provides 48 | 49 | == Development Goals (To-do's) 50 | 51 | - Keep the core framework in a single file 52 | - Keep the core components in another file 53 | - I have not done anything about exception handling (didn't wanted to litter the 54 | code base). Currently I'm always sending an HTTP 200 back or I'm just letting 55 | the app blow chuncks and showing rack's exception page 56 | - Radius usage is really entrenched in the current component implementation need 57 | to clean it up 58 | - Currently Trellis uses the Mongrel Rack Adapter. In the near future the 59 | particular web server would be configurable (one of the reasons to use Rack) 60 | 61 | == Classes 62 | 63 | Trellis::Application:: Base case for all Trellis applications 64 | Trellis::Page:: Base class for all application Pages 65 | Trellis::Renderer:: Renders XML/XHTML tags in the markup using Radius 66 | Trellis::Router:: Encapsulated the base route for a page 67 | Trellis::Component:: Base class for all Trellis components (work in progress) 68 | Trellis::DefaultRouter:: Encapsulates the default routing logic 69 | 70 | == Notes:: 71 | 72 | * Event model is pretty shallow right now. Basically events are just 73 | a convention of how the URLs are interpreted which results on a page method 74 | being invoked. A given URL contains information about the target page, event, 75 | source of the event and possible context values.This information is used to 76 | map to a single method in the page. 77 | * Navigation is a la Tapestry; Page methods can return the instance of a 78 | injected Page or they can return self in which case the same page is 79 | re-rendered. 80 | * Components can register their event handlers with the page. The page wraps the 81 | event handlers of the contained components and dispatches the events to the 82 | component instance. 83 | * Currently the Application is a single object, the multi-threading (which I had 84 | nothing to do with is provided by Rack) happens in the request dispatching. 85 | * Trellis is not a managed framework like Tapestry, in that sense it is more like 86 | Wicket. Pages instances are just created when needed, there is no pooling, 87 | or any of the complexity involved in activating/passivating objects to a pool. 88 | 89 | == Installation 90 | 91 | * gem install trellis 92 | 93 | A Trellis application consists of the Application class; a descendant of 94 | Trellis::Application and one or more pages; descendants of Trellis::Page. The 95 | Application at a minimum needs to declare the starting or home page: 96 | 97 | module Hello 98 | class HelloWorld < Trellis::Application 99 | home :home 100 | end 101 | 102 | class Home < Trellis::Page 103 | template do html { body { h1 "Hello World!" }} end 104 | end 105 | end 106 | 107 | To run the above application simply add the line: 108 | 109 | Hello::HelloWorld.new.start 110 | 111 | That will start the application on Mongrel running on port 3000 by default. To 112 | run on any other port pass the port number to the start method like: 113 | 114 | Hello::HelloWorld.new.start 8282 115 | 116 | == Required Gems 117 | 118 | rack => http://rack.rubyforge.org 119 | mongrel => http://mongrel.rubyforge.org 120 | radius => http://radius.rubyforge.org 121 | builder => http://builder.rubyforge.org 122 | paginator => http://paginator.rubyforge.org 123 | extensions => http://extensions.rubyforge.org 124 | haml => http://haml.hamptoncatlin.com 125 | markaby => http://code.whytheluckystiff.net/markaby 126 | nokogiri => http://nokogiri.org/ 127 | facets => http://facets.rubyforge.org/ 128 | directory_watcher => http://rubyforge.org/projects/codeforpeople 129 | erubis => http://www.kuwata-lab.com/erubis/ 130 | 131 | == LICENSE: 132 | 133 | (The MIT License) 134 | 135 | Copyright &169;2001-2010 Integrallis Software, LLC. 136 | 137 | Permission is hereby granted, free of charge, to any person obtaining 138 | a copy of this software and associated documentation files (the 139 | 'Software'), to deal in the Software without restriction, including 140 | without limitation the rights to use, copy, modify, merge, publish, 141 | distribute, sublicense, and/or sell copies of the Software, and to 142 | permit persons to whom the Software is furnished to do so, subject to 143 | the following conditions: 144 | 145 | The above copyright notice and this permission notice shall be 146 | included in all copies or substantial portions of the Software. 147 | 148 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 149 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 150 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 151 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 152 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 153 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 154 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 155 | 156 | == Contact 157 | 158 | Author:: Brian Sam-Bodden & the Folks at Integrallis 159 | Email:: bsbodden@integrallis.com 160 | Home Page:: http://trellisframework.org 161 | License:: MIT Licence (http://www.opensource.org/licenses/mit-license.html) -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | = Project: Trellis 2 | 3 | Trellis is a component-based Web Application Framework written in Ruby and based on Rack. 4 | Its main goal is to bring component-driven development to the micro-framework world. 5 | Trellis applications are composed of pages, pages have components, components emit events, 6 | pages and components can listen and handle events. 7 | Trellis aims to be a (close to) zero-configuration framework 8 | 9 | It draws inspiration from: 10 | 11 | Ruby Web Frameworks 12 | =================== 13 | * Rails 14 | * Camping 15 | * Merb 16 | * Iowa 17 | * Sinatra 18 | 19 | Java Web Frameworks 20 | =================== 21 | * Tapesty 22 | * Wicket 23 | 24 | Others 25 | ====== 26 | * Seaside 27 | 28 | == Goals 29 | Accomplished goals are marked with a (*) 30 | - * Pure HTML templates or in-line template creation with Markaby, HAML, erubis, Markdown and Textile 31 | - * To abstract away the request-response nature of web development and replace 32 | with events and listeners 33 | - * Reusable, extensible components including invisible components (behavior 34 | providers), tags (stateless components) or stateful components 35 | - * Easy component composition and markup inheritance 36 | - * Multi-threading support 37 | - * Heavy CoC :-) (Convention Over Configuration) ala Rails 38 | - * No static code generation, no generators, just a Ruby file! 39 | - * Component Libraries as Gems 40 | - Solid Ajax support attached to the event model using a single* massively tested 41 | Ajax framework/toolkit such as JQuery 42 | - Skinnable components a la DotNet. That is the ability to apply a theme to a 43 | page and cascade that to the contained components 44 | - Support for continuations in a componentized fashion (maybe) 45 | - CRUD behaviours for Pages/Components and using Datamapper under the covers 46 | - Web-based debugging and administration of the application similar to what 47 | Seaside provides 48 | 49 | == Development Goals (To-do's) 50 | 51 | - Keep the core framework in a single file 52 | - Keep the core components in another file 53 | - I have not done anything about exception handling (didn't wanted to litter the 54 | code base). Currently I'm always sending an HTTP 200 back or I'm just letting 55 | the app blow chuncks and showing rack's exception page 56 | - Radius usage is really entrenched in the current component implementation need 57 | to clean it up 58 | - Currently Trellis uses the Mongrel Rack Adapter. In the near future the 59 | particular web server would be configurable (one of the reasons to use Rack) 60 | 61 | == Classes 62 | 63 | Trellis::Application:: Base case for all Trellis applications 64 | Trellis::Page:: Base class for all application Pages 65 | Trellis::Renderer:: Renders XML/XHTML tags in the markup using Radius 66 | Trellis::Router:: Encapsulated the base route for a page 67 | Trellis::Component:: Base class for all Trellis components (work in progress) 68 | Trellis::DefaultRouter:: Encapsulates the default routing logic 69 | 70 | == Notes:: 71 | 72 | * Event model is pretty shallow right now. Basically events are just 73 | a convention of how the URLs are interpreted which results on a page method 74 | being invoked. A given URL contains information about the target page, event, 75 | source of the event and possible context values.This information is used to 76 | map to a single method in the page. 77 | * Navigation is a la Tapestry; Page methods can return the instance of a 78 | injected Page or they can return self in which case the same page is 79 | re-rendered. 80 | * Components can register their event handlers with the page. The page wraps the 81 | event handlers of the contained components and dispatches the events to the 82 | component instance. 83 | * Currently the Application is a single object, the multi-threading (which I had 84 | nothing to do with is provided by Rack) happens in the request dispatching. 85 | * Trellis is not a managed framework like Tapestry, in that sense it is more like 86 | Wicket. Pages instances are just created when needed, there is no pooling, 87 | or any of the complexity involved in activating/passivating objects to a pool. 88 | 89 | == Installation 90 | 91 | * gem install trellis 92 | 93 | A Trellis application consists of the Application class; a descendant of 94 | Trellis::Application and one or more pages; descendants of Trellis::Page. The 95 | Application at a minimum needs to declare the starting or home page: 96 | 97 | module Hello 98 | class HelloWorld < Trellis::Application 99 | home :home 100 | end 101 | 102 | class Home < Trellis::Page 103 | template do html { body { h1 "Hello World!" }} end 104 | end 105 | end 106 | 107 | To run the above application simply add the line: 108 | 109 | Hello::HelloWorld.new.start 110 | 111 | That will start the application on Mongrel running on port 3000 by default. To 112 | run on any other port pass the port number to the start method like: 113 | 114 | Hello::HelloWorld.new.start 8282 115 | 116 | == Required Gems 117 | 118 | rack => http://rack.rubyforge.org 119 | mongrel => http://mongrel.rubyforge.org 120 | radius => http://radius.rubyforge.org 121 | builder => http://builder.rubyforge.org 122 | paginator => http://paginator.rubyforge.org 123 | extensions => http://extensions.rubyforge.org 124 | haml => http://haml.hamptoncatlin.com 125 | markaby => http://code.whytheluckystiff.net/markaby 126 | nokogiri => http://nokogiri.org/ 127 | facets => http://facets.rubyforge.org/ 128 | directory_watcher => http://rubyforge.org/projects/codeforpeople 129 | erubis => http://www.kuwata-lab.com/erubis/ 130 | 131 | == LICENSE: 132 | 133 | (The MIT License) 134 | 135 | Copyright &169;2001-2010 Integrallis Software, LLC. 136 | 137 | Permission is hereby granted, free of charge, to any person obtaining 138 | a copy of this software and associated documentation files (the 139 | 'Software'), to deal in the Software without restriction, including 140 | without limitation the rights to use, copy, modify, merge, publish, 141 | distribute, sublicense, and/or sell copies of the Software, and to 142 | permit persons to whom the Software is furnished to do so, subject to 143 | the following conditions: 144 | 145 | The above copyright notice and this permission notice shall be 146 | included in all copies or substantial portions of the Software. 147 | 148 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 149 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 150 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 151 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 152 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 153 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 154 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 155 | 156 | == Contact 157 | 158 | Author:: Brian Sam-Bodden & the Folks at Integrallis 159 | Email:: bsbodden@integrallis.com 160 | Home Page:: http://trellisframework.org 161 | License:: MIT Licence (http://www.opensource.org/licenses/mit-license.html) -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'config/requirements' 2 | require 'config/hoe' # setup Hoe + all gem configuration 3 | 4 | Dir['tasks/**/*.rake'].each { |rake| load rake } 5 | 6 | task :default => :spec 7 | 8 | -------------------------------------------------------------------------------- /config/hoe.rb: -------------------------------------------------------------------------------- 1 | require 'trellis/version' 2 | 3 | AUTHOR = 'Brian Sam-Bodden' 4 | EMAIL = "bsbodden@integrallis.com" 5 | DESCRIPTION = "A component based web framework" 6 | GEM_NAME = 'trellis' 7 | RUBYFORGE_PROJECT = 'trellis' 8 | HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org" 9 | DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}" 10 | EXTRA_DEPENDENCIES = [ 11 | ['paginator', '>= 1.1.1'], 12 | ['rack', '>= 1.1.0'], 13 | ['radius', '>= 0.6.1'], 14 | ['builder', '>= 2.1.2'], 15 | ['nokogiri', '>= 1.4.1'], 16 | ['extensions', '>= 0.6.0'], 17 | ['haml', '>= 2.2.17'], 18 | ['markaby', '>= 0.5'], 19 | ['RedCloth', '>= 4.2.2'], 20 | ['bluecloth', '>= 2.0.5'], 21 | ['log4r', '>= 1.1.2'], 22 | ['facets', '>= 2.8.1'], 23 | ['directory_watcher', '>= 1.3.1'], 24 | ['eventmachine', '>= 0.12.10'], 25 | ['rack-cache', '>= 0.5.2'], 26 | ['rack-contrib', '>= 0.9.2'], 27 | ['rack-test', '>= 0.5.3'], 28 | ['erubis', '>= 2.6.5'], 29 | ['rspec', '>= 1.2.9'], 30 | ['newgem', '>= 1.5.2'], 31 | ['advisable', '>= 1.0.0'] 32 | ] # An array of rubygem dependencies [name, version] 33 | 34 | @config_file = "~/.rubyforge/user-config.yml" 35 | @config = nil 36 | RUBYFORGE_USERNAME = "bsbodden" 37 | def rubyforge_username 38 | unless @config 39 | begin 40 | @config = YAML.load(File.read(File.expand_path(@config_file))) 41 | rescue 42 | puts <<-EOS 43 | ERROR: No rubyforge config file found: #{@config_file} 44 | Run 'rubyforge setup' to prepare your env for access to Rubyforge 45 | - See http://newgem.rubyforge.org/rubyforge.html for more details 46 | EOS 47 | exit 48 | end 49 | end 50 | RUBYFORGE_USERNAME.replace @config["username"] 51 | end 52 | 53 | 54 | REV = nil 55 | VERS = Trellis::VERSION::STRING + (REV ? ".#{REV}" : "") 56 | RDOC_OPTS = ['--quiet', '--title', 'trellis documentation', 57 | "--opname", "index.html", 58 | "--line-numbers", 59 | "--main", "README", 60 | "--inline-source"] 61 | 62 | class Hoe 63 | def extra_deps 64 | @extra_deps.reject! { |x| Array(x).first == 'hoe' } 65 | @extra_deps 66 | end 67 | end 68 | 69 | # Generate all the Rake tasks 70 | # Run 'rake -T' to see list of generated tasks (from gem root directory) 71 | $hoe = Hoe.spec GEM_NAME do 72 | self.version = VERS 73 | self.developer(AUTHOR, EMAIL) 74 | self.description = DESCRIPTION 75 | self.summary = DESCRIPTION 76 | self.url = HOMEPATH 77 | self.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT 78 | self.test_globs = ["test/**/test_*.rb"] 79 | self.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean. 80 | 81 | # == Optional 82 | self.changes = paragraphs_of("History.txt", 0..1).join("\n\n") 83 | self.extra_deps = EXTRA_DEPENDENCIES 84 | end 85 | 86 | CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n") 87 | PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}" 88 | $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc') 89 | $hoe.rsync_args = '-av --delete --ignore-errors' 90 | $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue "" -------------------------------------------------------------------------------- /config/requirements.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | include FileUtils 3 | 4 | require 'rubygems' 5 | %w[rake hoe newgem rubigen].each do |req_gem| 6 | begin 7 | require req_gem 8 | rescue LoadError 9 | puts "This Rakefile requires the '#{req_gem}' RubyGem." 10 | puts "Installation: gem install #{req_gem} -y" 11 | exit 12 | end 13 | end 14 | 15 | $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib])) 16 | -------------------------------------------------------------------------------- /examples/crud_components/html/address_view_edit.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 |
12 | 13 | 14 |
18 |
19 |
Bad luck. You failed to guess that the word was
Better luck next time!
15 |Congratulations! You guessed that the word was
[
Word:
Are you ready to play? ...
15 | 16 |
17 |
You guessed the secret number in
[
Make a guess between one and ten:
12 |I'm thinking of a number between one and ten ...
14 | 15 |
16 |
The multicounter show multiple instances of a stateful component. It displays several instances of the same counter component.
17 |18 | 19 |
20 ||$!,'') 49 | end 50 | 51 | if ARGV.length >= 1 52 | src, template = ARGV 53 | template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb') 54 | else 55 | puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html") 56 | exit! 57 | end 58 | 59 | template = ERB.new(File.open(template).read) 60 | 61 | title = nil 62 | body = nil 63 | File.open(src) do |fsrc| 64 | title_text = fsrc.readline 65 | body_text_template = fsrc.read 66 | body_text = ERB.new(body_text_template).result(binding) 67 | syntax_items = [] 68 | body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)\1>!m){ 69 | ident = syntax_items.length 70 | element, syntax, source = $1, $2, $3 71 | syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}#{element}>" 72 | "syntax-temp-#{ident}" 73 | } 74 | title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip 75 | body = RedCloth.new(body_text).to_html 76 | body.gsub!(%r!(?:
)?syntax-temp-(\d+)(?:
)?!){ syntax_items[$1.to_i] }
77 | end
78 | stat = File.stat(src)
79 | created = stat.ctime
80 | modified = stat.mtime
81 |
82 | $stdout << template.result(binding)
83 |
--------------------------------------------------------------------------------
/tasks/deployment.rake:
--------------------------------------------------------------------------------
1 | desc 'Release the website and new gem version'
2 | task :deploy => [:check_version, :website, :release] do
3 | puts "Remember to create SVN tag:"
4 | puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
5 | "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
6 | puts "Suggested comment:"
7 | puts "Tagging release #{CHANGES}"
8 | end
9 |
10 | desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
11 | task :local_deploy => [:website_generate, :install_gem]
12 |
13 | task :check_version do
14 | unless ENV['VERSION']
15 | puts 'Must pass a VERSION=x.y.z release version'
16 | exit
17 | end
18 | unless ENV['VERSION'] == VERS
19 | puts "Please update your version.rb to match the release version, currently #{VERS}"
20 | exit
21 | end
22 | end
23 |
24 | desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
25 | task :install_gem_no_doc => [:clean, :package] do
26 | sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
27 | end
28 |
29 | namespace :manifest do
30 | desc 'Recreate Manifest.txt to include ALL files'
31 | task :refresh do
32 | `rake check_manifest | patch -p0 > Manifest.txt`
33 | end
34 | end
--------------------------------------------------------------------------------
/tasks/environment.rake:
--------------------------------------------------------------------------------
1 | task :ruby_env do
2 | RUBY_APP = if RUBY_PLATFORM =~ /java/
3 | "jruby"
4 | else
5 | "ruby"
6 | end unless defined? RUBY_APP
7 | end
8 |
--------------------------------------------------------------------------------
/tasks/rspec.rake:
--------------------------------------------------------------------------------
1 | begin
2 | require 'spec'
3 | rescue LoadError
4 | require 'rubygems'
5 | require 'spec'
6 | end
7 | begin
8 | require 'spec/rake/spectask'
9 | rescue LoadError
10 | puts <<-EOS
11 | To use rspec for testing you must install rspec gem:
12 | gem install rspec
13 | EOS
14 | exit(0)
15 | end
16 |
17 | desc "Run the specs under spec"
18 | Spec::Rake::SpecTask.new do |t|
19 | t.spec_opts = ['--options', "test/spec.opts"]
20 | t.spec_files = FileList['test/**/*_spec.rb']
21 | t.rcov = true
22 | end
--------------------------------------------------------------------------------
/tasks/website.rake:
--------------------------------------------------------------------------------
1 | desc 'Generate website files'
2 | task :website_generate => :ruby_env do
3 | (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
4 | sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
5 | end
6 | end
7 |
8 | desc 'Upload website files to rubyforge'
9 | task :website_upload do
10 | host = "#{rubyforge_username}@rubyforge.org"
11 | remote_dir = "/var/www/gforge-projects/#{PATH}/"
12 | local_dir = 'website'
13 | sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
14 | end
15 |
16 | desc 'Generate and upload website files'
17 | task :website => [:website_generate, :website_upload, :publish_docs]
18 |
--------------------------------------------------------------------------------
/test/application_spec.rb:
--------------------------------------------------------------------------------
1 | require File.dirname(__FILE__) + '/spec_helper.rb'
2 |
3 | require "rack"
4 | require 'rack/test'
5 | require_fixtures 'application_fixtures'
6 |
7 | describe Trellis::Application, " when declared" do
8 | before do
9 | @homepage = TestApp::MyApp.instance_eval { @homepage }
10 | @pages = TestApp::MyApp.instance_eval { @pages }
11 | @static_routes = TestApp::MyApp.instance_eval { @static_routes }
12 | end
13 |
14 | it "should contain a contain the symbol for its home page" do
15 | @homepage.should == :home
16 | end
17 |
18 | it "should contain any declared static routes" do
19 | images_route = @static_routes.select { |item| item[:urls].include?('/images') }
20 | images_route.should_not be_empty
21 | style_route = @static_routes.select { |item| item[:urls].include?('/style') }
22 | style_route.should_not be_empty
23 | favicon_route = @static_routes.select { |item| item[:urls].include?('/favicon.ico') }
24 | favicon_route.should_not be_empty
25 | jquery_route = @static_routes.select { |item| item[:urls].include?('/jquery') && item[:root].include?('./js') }
26 | jquery_route.should_not be_empty
27 | end
28 |
29 | it "should include Rack::Utils" do
30 | TestApp::MyApp.included_modules.should include(Rack::Utils)
31 | end
32 |
33 | end
34 |
35 | describe Trellis::Application, " when requesting the root url with a GET" do
36 | include Rack::Test::Methods
37 |
38 | def app
39 | TestApp::MyApp.new
40 | end
41 |
42 | it "should return an OK HTTP status" do
43 | get "/"
44 | last_response.status.should be(200)
45 | end
46 |
47 | it "should reply with the home page" do
48 | get "/"
49 | last_response.body.should == %[\n\n \n here's a value
\n \n\n" 154 | end 155 | 156 | it "should have access to any application public methods" do 157 | get "/application_method_page" 158 | last_response.body.should == "\n\n \nZaphod Beeblebrox
\n \n\n" 159 | end 160 | 161 | end 162 | 163 | describe Trellis::Application, " with declared partial views" do 164 | include Rack::Test::Methods 165 | 166 | def app 167 | TestApp::MyApp.new 168 | end 169 | 170 | it "should render a view defined in markaby" do 171 | get "/partial_markaby" 172 | last_response.body.should include("This content was generated by Markaby
") 173 | end 174 | 175 | it "should render a view defined in haml" do 176 | get "/partial_haml" 177 | last_response.body.should include("This content was generated by HAML
") 178 | end 179 | 180 | it "should render a view defined in textile" do 181 | get "/partial_textile" 182 | last_response.body.should include("This content was generated by Textile
") 183 | end 184 | 185 | it "should render a view defined in markdown" do 186 | get "/partial_markdown" 187 | last_response.body.should include("This content was generated by The Amazing ERubis
") 193 | end 194 | 195 | it "should render a view defined in eruby and have access to the surrounding context" do 196 | get "/partial_eruby_loop" 197 | last_response.body.join.should include("\n
Vulgar Vogons
") 222 | end 223 | 224 | it "should render and eruby template and layout" do 225 | get '/eruby_template_and_layout' 226 | last_response.body.join.should include("protected one
\n] 28 | end 29 | 30 | it "should be redirected by an around filter to a specific destination when using the get method" do 31 | get "/protected_two" 32 | redirect = last_response.headers['Location'] 33 | redirect.should == '/not_authorized' 34 | end 35 | 36 | it "should be allowed to process the get method by an around filter" do 37 | @app.allow = true 38 | get "/protected_two" 39 | last_response.body.should == %[\nprotected two
\n] 40 | end 41 | 42 | it "should apply filters only to the specified methods" do 43 | get "/protected_three" 44 | last_response.body.should == %[\nblah
\n] 45 | get "/protected_three/events/knock_knock" 46 | redirect = last_response.headers['Location'] 47 | redirect.should == '/not_authorized' 48 | end 49 | 50 | it "should allow to daisy chain filters" do 51 | @app.allow = true 52 | env = Hash.new 53 | env["rack.session"] = Hash.new 54 | get "/protected_three/events/knock_knock", {}, env 55 | redirect = last_response.headers['Location'] 56 | redirect.should eql('/protected_three') 57 | get redirect, {}, env 58 | last_response.body.should include("\n?ereht s'ohw
\n") 59 | end 60 | 61 | end -------------------------------------------------------------------------------- /test/fixtures/application_fixtures.rb: -------------------------------------------------------------------------------- 1 | module TestApp 2 | class MyApp < Trellis::Application 3 | home :home 4 | persistent :my_field 5 | 6 | map_static ['/images', '/style', '/favicon.ico'] 7 | map_static ['/jquery'], "./js" 8 | 9 | MY_CONSTANT_1 = "it's just us, chickens!" 10 | 11 | def application_method 12 | "Zaphod Beeblebrox" 13 | end 14 | 15 | partial :partial_markaby do p "This content was generated by Markaby" end 16 | partial :partial_haml, %[%p This content was generated by HAML], :format => :haml 17 | partial :partial_textile, %[This content was generated by *Textile*], :format => :textile 18 | partial :partial_markdown, %[# This content was generated by Markdown], :format => :markdown 19 | partial :partial_eruby, %[This content was generated by @{@my_variable}@
], :format => :eruby 20 | partial :loop_body, %[@!{@body}@
], :format => :eruby 23 | layout(:other) { thtml { body { render_body }}} 24 | end 25 | 26 | class Home < Trellis::Page 27 | pages :other 28 | 29 | template do html { body { h1 "Hello World!" }} end 30 | 31 | def on_event1 32 | self 33 | end 34 | 35 | def on_event2 36 | "just some text" 37 | end 38 | 39 | def on_event3 40 | @other 41 | end 42 | 43 | def on_event4(value) 44 | "the value is #{value}" 45 | end 46 | end 47 | 48 | class PageWithGetPlainText < Trellis::Page 49 | pages :other 50 | 51 | def get 52 | "some content" 53 | end 54 | end 55 | 56 | class PageWithGetRedirect < Trellis::Page 57 | pages :other 58 | 59 | def get 60 | @other 61 | end 62 | end 63 | 64 | class PageWithGetSame < Trellis::Page 65 | 66 | def get 67 | self 68 | end 69 | 70 | template do html { body { p "Vera, what has become of you?" }} end 71 | end 72 | 73 | class Other < Trellis::Page 74 | template do html { body { p "Goodbye Cruel World " }} end 75 | end 76 | 77 | class BeforeLoad < Trellis::Page 78 | attr_reader :some_value 79 | 80 | def before_load 81 | @some_value = "8675309" 82 | end 83 | 84 | template do thtml { body { text %[@{TestApp::MyApp::MY_CONSTANT_1}@
], :format => :eruby 285 | end 286 | 287 | class MethodAccessPage < Trellis::Page 288 | def greet 289 | "helloooo, la la la" 290 | end 291 | 292 | template %[@{greet}@
], :format => :eruby 293 | end 294 | 295 | class ApplicationDataPage < Trellis::Page 296 | 297 | def on_save 298 | @application.my_field = "here's a value" 299 | self 300 | end 301 | 302 | template %[@{@application.my_field}@
], :format => :eruby 303 | end 304 | 305 | class ApplicationMethodPage < Trellis::Page 306 | template %[@{application_method()}@
], :format => :eruby 307 | end 308 | 309 | class PageWithGetAndExplicitRedirect < Trellis::Page 310 | route '/explicit_redirect' 311 | 312 | def get 313 | redirect "/hello/Ford%20Prefect" 314 | end 315 | end 316 | 317 | class PartialMarkabyPage < Trellis::Page 318 | route '/partial_markaby' 319 | template %[@!{render_partial(:partial_markaby)}@], :format => :eruby 320 | end 321 | 322 | class PartialHamlPage < Trellis::Page 323 | route '/partial_haml' 324 | template %[@!{render_partial(:partial_haml)}@], :format => :eruby 325 | end 326 | 327 | class PartialTextilePage < Trellis::Page 328 | route '/partial_textile' 329 | template %[@!{render_partial(:partial_textile)}@], :format => :eruby 330 | end 331 | 332 | class PartialMarkdownPage < Trellis::Page 333 | route '/partial_markdown' 334 | template %[@!{render_partial(:partial_markdown)}@], :format => :eruby 335 | end 336 | 337 | class PartialErubyPage < Trellis::Page 338 | route '/partial_eruby' 339 | 340 | def get 341 | @my_variable = 'The Amazing ERubis' 342 | self 343 | end 344 | 345 | template %[@!{render_partial(:partial_eruby)}@], :format => :eruby 346 | end 347 | 348 | class PartialErubyLoopPage < Trellis::Page 349 | route '/partial_eruby_loop' 350 | 351 | def get 352 | @elements = ['ichi', 'ni', 'san', 'shi', 'go', 'rokku', 'hichi', 'hachi', 'kyu', 'jyu'] 353 | self 354 | end 355 | 356 | template %[ 357 | 358 |protected one
], :format => :html 18 | end 19 | 20 | class ProtectedTwo < Trellis::Page 21 | apply_filter :authorized?, :to => :all 22 | def get; self; end 23 | template %[protected two
], :format => :html 24 | end 25 | 26 | class ProtectedThree < Trellis::Page 27 | persistent :answer 28 | apply_filter :authorized?, :to => :on_knock_knock 29 | apply_filter :capitalize, :to => :on_knock_knock 30 | 31 | def initialize; @answer = "blah"; end 32 | 33 | def on_knock_knock 34 | @answer = "who's there?" 35 | self 36 | end 37 | 38 | template %[@{@answer}@
], :format => :eruby 39 | end 40 | 41 | class NotAuthorized < Trellis::Page 42 | template %[not authorized], :format => :html 43 | end 44 | end -------------------------------------------------------------------------------- /test/page_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/spec_helper.rb' 2 | 3 | require "rack" 4 | require "rack/test" 5 | require_fixtures 'application_fixtures' 6 | 7 | describe Trellis::Page, " when sending an event to a page" do 8 | include Rack::Test::Methods 9 | 10 | def app 11 | TestApp::MyApp.new 12 | end 13 | 14 | it "should redirect to the receiving page if the event handler returns self" do 15 | get "/home/events/event1" 16 | redirect = last_response.headers['Location'] 17 | redirect.should eql('/home') 18 | end 19 | 20 | it "should return a response as a string if the event handler returns a String" do 21 | get "/home/events/event2" 22 | last_response.body.should == "just some text" 23 | end 24 | 25 | it "should redirect to the injected page as a response if the event handler returns an injected page" do 26 | get "/home/events/event3" 27 | redirect = last_response.headers['Location'] 28 | redirect.should eql('/other') 29 | end 30 | 31 | it "should be able to pass a value as the last element or the URL" do 32 | get "/home/events/event4/quo%20vadis" 33 | last_response.body.should == "the value is quo vadis" 34 | end 35 | 36 | end 37 | 38 | describe Trellis::Page, " when calling inject_dependent_pages on an instance of Page" do 39 | it "should contain instances of the injected pages" do 40 | homepage = TestApp::Home.new 41 | homepage.inject_dependent_pages 42 | injected_page = homepage.instance_eval { @other } 43 | injected_page.should be_an_instance_of(TestApp::Other) 44 | end 45 | end 46 | 47 | describe Trellis::Page, " when created with a custom route" do 48 | it "should contain an instance of Router" do 49 | router = TestApp::RoutedDifferently.router 50 | router.should_not be_nil 51 | router.should be_an_instance_of(Trellis::Router) 52 | end 53 | end 54 | 55 | describe Trellis::Page, " when provided with a #get method" do 56 | include Rack::Test::Methods 57 | 58 | def app 59 | TestApp::MyApp.new 60 | end 61 | 62 | it "should redirect to the page returned" do 63 | get "/page_with_get_redirect" 64 | redirect = last_response.headers['Location'] 65 | redirect.should eql('/other') 66 | end 67 | 68 | it "should return a response as a string if the ==get== methood returns a String" do 69 | get "/page_with_get_plain_text" 70 | last_response.body.should == "some content" 71 | end 72 | 73 | it "should render the result of the ==get== method if it is the same page" do 74 | get "/page_with_get_same" 75 | last_response.body.should include("Vera, what has become of you?
") 76 | end 77 | end 78 | 79 | describe Trellis::Page, " when given a template" do 80 | include Rack::Test::Methods 81 | 82 | def app 83 | TestApp::MyApp.new 84 | end 85 | 86 | it "should rendered it correctly if it is in HAML format" do 87 | get "/haml_page" 88 | last_response.body.should include(%[\n HAML rocks!\n
]) 89 | end 90 | 91 | it "should rendered it correctly if it is in Textile format" do 92 | get "/textile_page" 93 | last_response.body.should == "\nA simple example.
\n" 94 | end 95 | 96 | it "should rendered it correctly if it is in Markdown format" do 97 | get "/mark_down_page" 98 | last_response.body.should include(%[body>This is some text]) 99 | end 100 | 101 | it "should rendered it correctly if it is in ERuby format" do 102 | get "/e_ruby_page" 103 | last_response.body.should include("
it's just us, chickens!
") 129 | end 130 | 131 | it "should have access to application methods in ERuby format" do 132 | get "/method_access_page" 133 | last_response.body.should include("helloooo, la la la
") 134 | end 135 | 136 | it "should invoke the before_load method if provided by the page" do 137 | get "/before_load" 138 | last_response.body.should include("8675309") 139 | end 140 | 141 | it "should invoke the after_load method if provided by the page" do 142 | get "/after_load" 143 | last_response.body.should include("chunky bacon!") 144 | end 145 | 146 | it "should invoke the before_render method if provided by the page" do 147 | get "/before_render" 148 | last_response.body.should include("8675309") 149 | end 150 | 151 | it "should invoke the after_render method if provided by the page" do 152 | env = Hash.new 153 | env["rack.session"] = Hash.new 154 | get "/after_render", {}, env 155 | env["rack.session"][:my_field].should include("changed in after_render method") 156 | end 157 | 158 | it "should redirect if giving an explicit redirect" do 159 | get '/explicit_redirect' 160 | redirect = last_response.headers['Location'] 161 | redirect.should eql('/hello/Ford%20Prefect') 162 | get redirect 163 | last_response.body.should include("