@options
hash in the constructor since we cannot rely on cells anymore.
37 |
38 | h2. 1.2.0
39 |
40 | h3. Changes
41 | * The @Widget.new@ constructor now expects the parent widget as first argument (except for the root widget, which still gets the damned ActionController instance). Nobody needed orphaned widgets so far so we decided to make it simpler. This makes the @#<<@ method a DSL-method, only.
42 | * You can now access the root widget instance (or any other parent widget) in any subsequent @has_widgets@ block. This fixes "a famous issue":https://github.com/apotonick/apotomo/issues/34 and makes the @:passing@ option work as expected at every tree level.
43 | * The @#widget@ shortcut method no longer returns a valid widget instance but a DSL-specific thing. Use the real constructor form if you need it right away (@MouseWidget.new(parent, :kid)@) or access the instance afterwards (@root[:kid]@).
44 | * Removed the @after_add@ hook. Now that adding happens in the constructor, hook into @after_initialize@.
45 | * Removed @#param@ in favor of @#options@.
46 | * Removed @#emit@ in favor of @#render@.
47 | * Removed @#remove_all!@ and @#remove_from_parent!@. Did you ever use these?
48 |
49 | h2. 1.1.4
50 |
51 | h3. Changes
52 | * New signature: @TestCase#trigger(type, source, options)@. This method no longer messes around with the widget's options hash but simply passes any additional options to @evt#data@. Also, the event @source@ is now the required second argument.
53 | * We now got @TestCase#view_assigns@ to access instance variables from the last rendered widget.
54 |
55 | h2. 1.1.1
56 |
57 | h3. Additions
58 | * You can now attach event handlers to other widgets simply by using the @:passing@ option: @responds_to_event :click, :passing => :root@.
59 | * If you want to debug events, just include the (WIP) @apotomo/debugging@ file and watch your server output on the console.
60 |
61 | h3. Changes
62 | * @Widget.responds_to_event@ is inheritable now.
63 | * The generator now places namespaced widgets into the correct sub-directories.
64 |
65 | h3. Removals
66 | * Removed the alias @Widget.respond_to_event@, please use @Widget.responds_to_event@.
67 |
68 | h2. 1.1
69 |
70 | h3. Changes
71 | * Widgets now reside in @app/widgets/@ and have the @Widget@ appendix per convention, identical to cells and controllers. This introduces the following changes, illustrated with an imaginary @CommentsWidget@:
72 | ** @widget(:comments, ...)@ will search and instantiate @CommentsWidget@ (note the missing "Widget").
73 | ** The @CommentsWidget@ views are searched in @app/widgets/comments/@ (note the missing "_widget").
74 | * Including Apotomo::Rails::ControllerMethods by hand is optional. The first call to Controller.has_widgets will include the real module.
75 | * You can now @#render_widget@ in your widget views to render children.
76 | * @#widget@ now accepts one arg only (the widget prefix). @widget(:comments)@ sets id to @:comments@. We also removed the start state argument.
77 | * Start states are no longer accepted, you have to explicitely pass the state to #render_widget. That's why #invoke now requires an explicit state as well.
78 | * #replace/#update now append a @;@ to the JavaScript expression. You may pass an arbitrary selector string as first argument (optional).
79 | * The event is no longer added to #options at triggering time.
80 | * Options passed in #render_widget are no longer merged with #options. They are passed as state-args to reduce complexity.
81 | * We no longer have @opts and @params but #options and #params from Cell::Base.
82 | * The params hash is appended to the event in RequestProcessor#process_for. You can now live completely without accessing the global #params.
83 | * #respond/#update with :selector does not longer prefix the selector with #. It's up to you.
84 | * Event delegates #[] to #data.
85 |
86 | h3. Removals
87 | * Removed #param, it is simply too complex.
88 | * Removed render :render_children and :invoke options. Use #render_widget in your state/view.
89 | * Removed render :suppress_js as it was ugly and kills children.
90 | * Removed #jump_to_state and #last_state.
91 | * Removed `@cell`, now longer available in state views.
92 | * Removed #cell, #container and #section widget shortcuts.
93 | * Removed @rendered_children@ local in views. Use #render_widget.
94 | * Removed ContainerWidget, nobody needs it.
95 |
96 | h3. Bugfixes
97 | * Widget.responds_to_event no longer shares its options with multiple widget instances of the same class.
98 |
99 |
100 | h2. 1.0.4
101 |
102 | h3. Bugfixes
103 | * Caching states works, again. Thanks to Gudleik Rasch for spotting.
104 | * We cleanly require cells-3.4.x now. Thanks to Ryan Bates who remarked that Apotomo 1.0.x tries to require cells-3.5, which was wrong.
105 |
106 | h3. Notes
107 |
108 | * Removed the usage of state-args. If you want the event instance in your triggered state, use @opts[:event] or upgrade to apotomo-1.1.
109 |
110 |
111 | h2. 1.0.3
112 |
113 | h3. Bugfixes
114 | * fixed gemspec to not require useless gem dependencies.
115 |
116 |
117 | h2. 1.0.2
118 |
119 | h3. Changes
120 | * removals from ViewHelper: #trigger_event, #form_to_event and friends as they use deprecated Rails helpers.
121 |
122 | h3. Bugfixes
123 | * Widget#fire now accepts payload data for the fired event.
124 | * triggered states now receive the event object if they expect one argument.
125 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "http://rubygems.org"
2 |
3 | gemspec
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Apotomo
2 |
3 | **Web Components for Rails.**
4 |
5 |
6 | ## Overview
7 |
8 | Do you need an _interactive user interface_ for your Rails application? A cool Rich Client Application with dashboards, portlets and AJAX, Drag&Drop and jQuery?
9 |
10 | Is your controller gettin' fat? And your partial-helper-AJAX pile is getting out of control?
11 |
12 | Do you want a framework to make the implementation easier? _You want Apotomo._
13 |
14 | **Apotomo** is based on [Cells](http://github.com/apotonick/cells), the popular View Components framework for Rails.
15 |
16 | It gives you widgets and encapsulation, bubbling events, AJAX page updates, rock-solid testing and more. Check out I'm wrapped
51 | # 52 | # 53 | # Note that you can set the +id+ and other options manually. 54 | # 55 | # - widget_tag :div, id: "comments", class: "yellow" 56 | def widget_tag(tag, options={}, &block) 57 | options.reverse_merge!(:id => widget_id) 58 | 59 | content_tag(tag, options, &block) 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/apotomo/railtie.rb: -------------------------------------------------------------------------------- 1 | require "rails/railtie" 2 | 3 | module Apotomo 4 | class Railtie < ::Rails::Railtie 5 | rake_tasks do 6 | load "apotomo/apotomo.rake" 7 | end 8 | 9 | # As we are a Railtie only, the routes won't be loaded automatically. Beside that, we want our 10 | # route to be the very first (otherwise #resources might supersede it). 11 | initializer 'apotomo.prepend_routes', :after => :add_routing_paths do |app| 12 | app.routes_reloader.paths.unshift(File.dirname(__FILE__) + "/../../config/routes.rb") 13 | end 14 | 15 | # Include a lazy loader via has_widgets. 16 | initializer 'apotomo.add_has_widgets' do |app| 17 | ActionController::Base.extend Apotomo::Rails::ControllerMethodsLoader 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/apotomo/request_processor.rb: -------------------------------------------------------------------------------- 1 | module Apotomo 2 | class RequestProcessor 3 | 4 | class InvalidSourceWidget < RuntimeError; end 5 | 6 | include Hooks 7 | 8 | define_hook :after_initialize 9 | define_hook :after_fire 10 | 11 | attr_reader :root 12 | 13 | 14 | def initialize(controller, options={}, has_widgets_blocks=[]) 15 | @root = Widget.new(controller, :root) 16 | 17 | attach_stateless_blocks_for(has_widgets_blocks, @root, controller) 18 | 19 | run_hook :after_initialize, self 20 | end 21 | 22 | def attach_stateless_blocks_for(blocks, root, controller) 23 | blocks.each { |blk| controller.instance_exec(root, &blk) } 24 | end 25 | 26 | # Called when the browser wants an url_for_event address. This fires the request event in 27 | # the widget tree and collects the rendered page updates. 28 | def process_for(request_params) 29 | source = self.root.find_widget(request_params[:source]) or raise InvalidSourceWidget, "Source #{request_params[:source].inspect} non-existent." 30 | 31 | source.fire(request_params[:type].to_sym, request_params) # set data to params for now. 32 | 33 | run_hook :after_fire, self 34 | source.root.page_updates ### DISCUSS: that's another dependency. 35 | end 36 | 37 | # Renders the widget named +widget_id+. Any additional args is passed through to Widget#invoke. 38 | def render_widget_for(*args) 39 | root.render_widget(*args) 40 | end 41 | 42 | # Computes the address hash for a +:source+ widget and an event +:type+. 43 | # Additional parameters will be merged. 44 | def address_for(options) # DISCUSS: remove/make private/rename? 45 | raise "You forgot to provide :source or :type" unless options.has_key?(:source) and options.has_key?(:type) 46 | options 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/apotomo/test_case.rb: -------------------------------------------------------------------------------- 1 | require 'cell/test_case' 2 | 3 | module Apotomo 4 | # Testing is fun. Test your widgets! 5 | # 6 | # This class helps you testing widgets where it can. It is similar as in a controller. 7 | # A declarative test would look like 8 | # 9 | # class BlogWidgetTest < Apotomo::TestCase 10 | # has_widgets do |root| 11 | # root << widget(:comments_widget, 'post-comments') 12 | # end 13 | # 14 | # it "should be rendered nicely" do 15 | # render_widget 'post-comments' 16 | # 17 | # assert_select "div#post-comments", "Comments for this post" 18 | # end 19 | # 20 | # it "should redraw on :update" do 21 | # trigger :update 22 | # assert_response "jQuery(\"post-comments\").update ..." 23 | # end 24 | # 25 | # For unit testing, you can grab an instance of your tested widget. 26 | # 27 | # it "should be visible" do 28 | # assert root['post-comments'].visible? 29 | # end 30 | # 31 | # See also in Cell::TestCase. 32 | class TestCase < Cell::TestCase # TODO: re-arrange modules in Cell::TestCase and include instead of inheritance. 33 | # Generic test methods to be used in Test::Unit, RSpec, etc. 34 | module TestMethods 35 | extend ActiveSupport::Concern 36 | 37 | include Cell::TestCase::CommonTestMethods 38 | 39 | attr_reader :view_assigns 40 | 41 | def setup 42 | super # defined in Cell::TestCase::CommonTestMethods. 43 | 44 | @controller.instance_eval do 45 | def controller_path 46 | 'barn' 47 | end 48 | end 49 | @controller.extend Apotomo::Rails::ControllerMethods 50 | end 51 | 52 | # Renders the widget +name+. 53 | def render_widget(*args) 54 | @view_assigns = extract_state_ivars_for(root[args.first]) do 55 | @last_invoke = root.render_widget(*args) 56 | end 57 | cleanup_assigns!(@view_assigns) 58 | 59 | @last_invoke 60 | end 61 | 62 | # Triggers an event of +type+. You have to pass the +source+ as second options. 63 | # 64 | # Example: 65 | # 66 | # trigger :submit, :comments 67 | def trigger(type, source, options={}) 68 | source = root.find_widget(source) 69 | source.fire(type, options) 70 | root.page_updates 71 | end 72 | 73 | # Returns the widget tree from TestCase.has_widgets. 74 | def root 75 | blk = self.class.has_widgets_blocks or raise "Please setup a widget tree using has_widgets()" 76 | @root ||= Apotomo::Widget.new(parent_controller, "root").tap do |root| 77 | self.instance_exec(root, &blk) 78 | end 79 | end 80 | 81 | def parent_controller 82 | @controller 83 | end 84 | 85 | private 86 | def cleanup_assigns!(assigns) 87 | assigns.delete(:lookup_context) # dirty but it works. 88 | end 89 | 90 | module ClassMethods 91 | def has_widgets_blocks 92 | @has_widgets 93 | end 94 | 95 | # Setup a widget tree as you're used to it from your controller. Executed in test context. 96 | def has_widgets(&block) 97 | @has_widgets = block 98 | end 99 | end 100 | end 101 | 102 | # After a #trigger this assertion compares the actually triggered page updates with the passed. 103 | # 104 | # Example: 105 | # 106 | # trigger :submit, :source => "post-comments" 107 | # assert_response "alert(\":submit clicked!\")", /\jQuery\("post-comments"\).update/ 108 | def assert_response(*content) 109 | updates = root.page_updates 110 | 111 | i = 0 112 | content.each do |assertion| 113 | if assertion.kind_of? Regexp 114 | assert_match assertion, updates[i] 115 | else 116 | assert_equal assertion, updates[i] 117 | end 118 | 119 | i+=1 120 | end 121 | end 122 | 123 | include Apotomo::WidgetShortcuts 124 | include TestMethods 125 | end 126 | end 127 | -------------------------------------------------------------------------------- /lib/apotomo/version.rb: -------------------------------------------------------------------------------- 1 | module Apotomo 2 | VERSION = '1.3.2' 3 | end 4 | -------------------------------------------------------------------------------- /lib/apotomo/widget.rb: -------------------------------------------------------------------------------- 1 | require 'cells' 2 | require 'onfire' 3 | require 'hooks' 4 | 5 | 6 | require 'apotomo/event' 7 | require 'apotomo/widget_shortcuts' 8 | require 'apotomo/rails/view_helper' 9 | require 'apotomo/rails/controller_methods' # FIXME. 10 | 11 | require 'apotomo/widget/tree_node' 12 | require 'apotomo/widget/event_methods' 13 | require 'apotomo/widget/javascript_methods' 14 | 15 | 16 | module Apotomo 17 | # == Accessing Parameters 18 | # 19 | # Apotomo tries to prevent you from having to access the global #params hash. We have the following 20 | # concepts to retrieve input data. 21 | # 22 | # 1. Configuration values are available both in render and triggered states. Pass those in #widget 23 | # when creating the widget tree. Use #options for reading. 24 | # 25 | # has_widgets do |root| 26 | # root << widget(:mouse_widget, 'mum', :favorites => ["Gouda", "Chedar"]) 27 | # 28 | # and read in your widget state 29 | # 30 | # def display 31 | # @cheese = options[:favorites].first 32 | # 33 | # 2. Request data from forms etc. is available through event.data in the triggered states. 34 | # Use the #[] shortcut to access values directly. 35 | # 36 | # def update(evt) 37 | # @cheese = Cheese.find evt[:cheese_id] 38 | class Widget < Cell::Rails 39 | self.view_paths = "app/widgets" 40 | 41 | include Hooks 42 | 43 | # Use this for setup code you're calling in every state. Almost like a +before_filter+ except that it's 44 | # invoked after the initialization in #has_widgets. 45 | # 46 | # Example: 47 | # 48 | # class MouseWidget < Apotomo::Widget 49 | # after_initialize do 50 | # @cheese = Cheese.find options[:cheese_id] 51 | # end 52 | define_hook :after_initialize 53 | define_hook :has_widgets 54 | 55 | attr_writer :visible 56 | 57 | include TreeNode 58 | 59 | include Onfire 60 | 61 | include EventMethods 62 | include WidgetShortcuts 63 | include JavascriptMethods 64 | 65 | helper Apotomo::Rails::ViewHelper 66 | helper Apotomo::Rails::ActionViewMethods 67 | 68 | abstract! 69 | undef :display # We don't want #display to be listed in #internal_methods. 70 | 71 | attr_reader :name 72 | alias_method :widget_id, :name 73 | 74 | attr_reader :options 75 | 76 | after_initialize do 77 | run_hook :has_widgets, self 78 | end 79 | 80 | 81 | def initialize(parent, id, options={}) 82 | super(parent) # TODO: do that as long as cells do need a parent_controller. 83 | @options = options 84 | @name = id 85 | @visible = true 86 | 87 | setup_tree_node(parent) 88 | 89 | run_hook :after_initialize, self 90 | end 91 | 92 | def parent_controller 93 | # i hope we'll get rid of any parent_controller dependency, soon. 94 | root? ? @parent_controller : root.parent_controller 95 | end 96 | 97 | def visible? 98 | @visible 99 | end 100 | 101 | # Invokes +state+ and hopefully returns the rendered content. 102 | def invoke(state, *args) 103 | return render_state(state, *args) if method(state).arity != 0 # TODO: remove check and make trigger states receive the evt default. 104 | render_state(state) 105 | end 106 | 107 | # Renders and returns a view for the current state. That's why it is usually called at the end of 108 | # a state method. 109 | # 110 | # ==== Options 111 | # * See http://rdoc.info/gems/cells/Cell/Rails:render 112 | # 113 | # Example: 114 | # class MouseWidget < Apotomo::Widget 115 | # def eat 116 | # render 117 | # end 118 | # 119 | # render the view eat.haml. 120 | # 121 | # render :text => "alert('SQUEAK!');" 122 | # 123 | # issues a squeaking alert dialog on the page. 124 | def render(*args, &block) 125 | super 126 | end 127 | 128 | # Returns the widget named +widget_id+ if it's a descendent or self. 129 | def find_widget(widget_id) 130 | find {|node| node.name.to_s == widget_id.to_s} 131 | end 132 | 133 | def address_for_event(type, options={}) 134 | options.reverse_merge! :source => name, 135 | :type => type, 136 | :controller => parent_controller.controller_path # DISCUSS: dependency to parent_controller. 137 | end 138 | 139 | def url_for_event(type, options={}) 140 | apotomo_event_path address_for_event(type, options) 141 | end 142 | 143 | 144 | def self.controller_path 145 | @controller_path ||= name.sub(/Widget$/, '').underscore unless anonymous? 146 | end 147 | 148 | # Renders the +widget+ (instance or id). 149 | def render_widget(widget_id, state=:display, *args) 150 | if widget_id.kind_of?(Widget) 151 | widget = widget_id 152 | else 153 | widget = find_widget(widget_id) or raise "Couldn't render non-existent widget `#{widget_id}`" 154 | end 155 | 156 | widget.invoke(state, *args) 157 | end 158 | end 159 | end 160 | 161 | -------------------------------------------------------------------------------- /lib/apotomo/widget/event_methods.rb: -------------------------------------------------------------------------------- 1 | require 'apotomo/invoke_event_handler' 2 | 3 | module Apotomo 4 | # Event-related methods and onfire bridge for Widget. 5 | module EventMethods 6 | extend ActiveSupport::Concern 7 | 8 | included do 9 | after_initialize do 10 | self.class.responds_to_event_options.each do |args| 11 | type, options = args[0], args[1] || {} 12 | target = self 13 | 14 | if target_id = options[:passing] 15 | target = root.find_widget(target_id) 16 | options = options.reverse_merge(on: widget_id) 17 | end 18 | 19 | target.respond_to_event(type, options) 20 | end 21 | end 22 | 23 | inheritable_attr :responds_to_event_options 24 | self.responds_to_event_options = [] 25 | end 26 | 27 | 28 | attr_writer :page_updates 29 | 30 | def page_updates 31 | @page_updates ||= [] 32 | end 33 | 34 | 35 | module ClassMethods 36 | # Instructs the widget to look out for +type+ events. If an appropriate event starts from or passes the widget, 37 | # the defined trigger state is executed. 38 | # 39 | # class MouseWidget < Apotomo::Widget 40 | # responds_to_event :squeak 41 | # 42 | # def squeak(evt) 43 | # update 44 | # end 45 | # 46 | # Calls #squeak when a :squeak event is encountered. 47 | # 48 | # == Options 49 | # Any option except the event +type+ is optional. 50 | # 51 | # [:with => state] 52 | # executes +state+, defaults to +type+. 53 | # responds_to_event :squeak, :with => :chirp 54 | # will invoke the +#chirp+ state method. 55 | # [:on => id] 56 | # execute the trigger state on another widget. 57 | # responds_to_event :squeak, :on => :cat 58 | # will invoke the +#squeak+ state on the +:cat+ widget. 59 | # [:from => id] 60 | # executes the state only if the event origins from +id+. 61 | # responds_to_event :squeak, :from => :kid 62 | # will invoke the +#squeak+ state if +:kid+ triggered and if +:kid+ is a decendent of the current widget. 63 | # [:passing => id] 64 | # attaches the observer to another widget. Useful if you want to catch bubbling events in +root+. 65 | # responds_to_event :squeak, :passing => :root 66 | # will invoke the state on the current widget if the event passes +:root+ (which is highly probable). 67 | # 68 | # == Inheritance 69 | # Note that the observers are inherited. This allows deriving a widget class without having to redefine the 70 | # responds_to_event blocks. 71 | def responds_to_event(*options) 72 | responds_to_event_options << options 73 | end 74 | end 75 | 76 | # Same as #responds_to_event but executed on the widget instance, only. 77 | def respond_to_event(type, options={}) 78 | # DISCUSS: do we need the :once option? how could we avoid re-adding? 79 | options = options.reverse_merge(:once => true, 80 | :with => type, 81 | :on => widget_id) 82 | 83 | handler = InvokeEventHandler.new(:widget_id => options[:on], :state => options[:with]) 84 | return if options[:once] and event_table.all_handlers_for(type, options[:from]).include?(handler) 85 | 86 | on(type, :call => handler, :from => options[:from]) 87 | end 88 | 89 | # Fire an event of +type+ and let it bubble up. You may add arbitrary payload data to the event. 90 | # 91 | # Example: 92 | # 93 | # trigger(:dropped, :area => 59) 94 | # 95 | # which can be queried in a triggered state. 96 | # 97 | # def on_drop(event) 98 | # if event[:area] == 59 99 | def trigger(*args) 100 | fire(*args) 101 | end 102 | 103 | # Get all handlers from self for the passed event (overriding Onfire#local_event_handlers). 104 | def handlers_for_event(event) 105 | event_table.all_handlers_for(event.type, event.source.name) # we key with widget_id. 106 | end 107 | 108 | protected 109 | def event_for(*args) # defined in Onfire: we want Apotomo::Event. 110 | Event.new(*args) 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /lib/apotomo/widget/javascript_methods.rb: -------------------------------------------------------------------------------- 1 | module Apotomo 2 | module JavascriptMethods 3 | # Returns the escaped script. 4 | def escape_js(script) 5 | Apotomo.js_generator.escape(script) 6 | end 7 | 8 | # Wraps the rendered content in a replace statement according to your +Apotomo.js_framework+ setting. 9 | # Received the same options as #render plus an optional +selector+ to change the selector. 10 | # 11 | # Example (with Apotomo.js_framework = :jquery): 12 | # 13 | # def hungry 14 | # replace 15 | # 16 | # will render the current state's view and wrap it like 17 | # 18 | # "jQuery(\"#mouse\").replaceWith(\"7 | Find me in <%= @path %> 8 |
9 | <%% end %> 10 | -------------------------------------------------------------------------------- /lib/generators/templates/view.haml: -------------------------------------------------------------------------------- 1 | = widget_div do 2 | %h1 3 | <%= class_name %>Widget#<%= @state %> 4 | %p 5 | Find me in <%= @path %> 6 | -------------------------------------------------------------------------------- /lib/generators/templates/view.slim: -------------------------------------------------------------------------------- 1 | = widget_div do 2 | h1 <%= class_name %>Widget#<%= @state %> 3 | p Find me in <%= @path %> 4 | -------------------------------------------------------------------------------- /lib/generators/templates/widget.rb: -------------------------------------------------------------------------------- 1 | class <%= class_name %>Widget < Apotomo::Widget 2 | 3 | <% for action in actions -%> 4 | def <%= action %> 5 | render 6 | end 7 | 8 | <% end -%> 9 | end 10 | -------------------------------------------------------------------------------- /lib/generators/templates/widget_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class <%= class_name %>WidgetTest < Apotomo::TestCase 4 | has_widgets do |root| 5 | root << widget(:<%= file_name %>) 6 | end 7 | 8 | test "display" do 9 | render_widget :<%= file_name %> 10 | assert_select "h1" 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/generators/test_unit/widget_generator.rb: -------------------------------------------------------------------------------- 1 | require 'generators/cells/base' 2 | 3 | module TestUnit 4 | module Generators 5 | class WidgetGenerator < ::Cells::Generators::Base 6 | source_root File.expand_path('../../templates', __FILE__) 7 | 8 | def create_test 9 | @states = actions 10 | template 'widget_test.rb', File.join('test/widgets/', class_path, "#{file_name}_widget_test.rb") 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/apotomo_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ApotomoTest < MiniTest::Spec 4 | describe "The main module ::Apotomo" do 5 | describe "when setting #js_framework" do 6 | before do 7 | Apotomo.js_framework = :jquery 8 | end 9 | 10 | it "respond to #js_framework and return javascript framework's name" do 11 | assert_equal :jquery, Apotomo.js_framework 12 | end 13 | 14 | it "respond to #js_generator and return an correct instance" do 15 | assert_kind_of Apotomo::JavascriptGenerator, Apotomo.js_generator 16 | assert_kind_of Apotomo::JavascriptGenerator::Jquery, Apotomo.js_generator 17 | end 18 | end 19 | 20 | it "respond to #setup" do 21 | Apotomo.setup do |config| 22 | config.js_framework = :jquery 23 | end 24 | 25 | # TODO: Apotomo expect #js_framework 26 | assert_respond_to Apotomo.js_generator, :jquery 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | require 'rake' 6 | 7 | Dummy::Application.load_tasks 8 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |You may have mistyped the address or the page may have moved.
24 |Maybe you tried to change something you didn't have access to.
24 |We've been notified about this issue and we'll take a look at it shortly.
24 |) 20 | assert_file "app/widgets/gerbil/squeak.html.erb", %r(app/widgets/gerbil/squeak\.html\.erb) 21 | 22 | assert_file "test/widgets/gerbil_widget_test.rb", %r(class GerbilWidgetTest < Apotomo::TestCase) 23 | assert_file "test/widgets/gerbil_widget_test.rb", %r(widget\(:gerbil\)) 24 | end 25 | 26 | test "create haml assets with -e haml" do 27 | run_generator %w(Gerbil squeak snuggle -e haml -t test_unit) 28 | 29 | assert_file "app/widgets/gerbil_widget.rb", /class GerbilWidget < Apotomo::Widget/ 30 | assert_file "app/widgets/gerbil_widget.rb", /def snuggle/ 31 | assert_file "app/widgets/gerbil_widget.rb", /def squeak/ 32 | assert_file "app/widgets/gerbil/snuggle.html.haml", %r(app/widgets/gerbil/snuggle\.html\.haml) 33 | assert_file "app/widgets/gerbil/snuggle.html.haml", %r(%p) 34 | assert_file "app/widgets/gerbil/squeak.html.haml", %r(app/widgets/gerbil/squeak\.html\.haml) 35 | assert_file "test/widgets/gerbil_widget_test.rb" 36 | end 37 | 38 | test "create slim assets with -e slim" do 39 | run_generator %w(Gerbil squeak snuggle -e slim -t test_unit) 40 | 41 | assert_file "app/widgets/gerbil_widget.rb", /class GerbilWidget < Apotomo::Widget/ 42 | assert_file "app/widgets/gerbil_widget.rb", /def snuggle/ 43 | assert_file "app/widgets/gerbil_widget.rb", /def squeak/ 44 | assert_file "app/widgets/gerbil/snuggle.html.slim", %r(app/widgets/gerbil/snuggle\.html\.slim) 45 | assert_file "app/widgets/gerbil/snuggle.html.slim", %r(p) 46 | assert_file "app/widgets/gerbil/squeak.html.slim", %r(app/widgets/gerbil/squeak\.html\.slim) 47 | assert_file "test/widgets/gerbil_widget_test.rb" 48 | end 49 | 50 | test "work with namespaces" do 51 | run_generator %w(Gerbil::Mouse squeak -t test_unit) 52 | 53 | assert_file "app/widgets/gerbil/mouse_widget.rb", /class Gerbil::MouseWidget < Apotomo::Widget/ 54 | assert_file "app/widgets/gerbil/mouse_widget.rb", /def squeak/ 55 | assert_file "app/widgets/gerbil/mouse/squeak.html.erb", %r(app/widgets/gerbil/mouse/squeak\.html\.erb) 56 | assert_file "test/widgets/gerbil/mouse_widget_test.rb" 57 | end 58 | 59 | # end 60 | # end 61 | end 62 | -------------------------------------------------------------------------------- /test/render_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class RenderTest < MiniTest::Spec 4 | include Apotomo::TestCaseMethods::TestController 5 | 6 | describe "#render" do 7 | before do 8 | @mum = mouse('mum') 9 | end 10 | 11 | it "per default display the state content framed in a div" do 12 | assert_equal '