merb_component 0.2.3
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/LICENSE +20 -0
- data/README +34 -0
- data/Rakefile +87 -0
- data/TODO +5 -0
- data/lib/merb_component.rb +20 -0
- data/lib/merb_component/controller_ext.rb +217 -0
- data/lib/merb_component/merbtasks.rb +6 -0
- data/lib/merb_component/resource_ext.rb +11 -0
- data/lib/merb_component/router_ext.rb +8 -0
- data/spec/admin_spec.rb +106 -0
- data/spec/fixture/app/controllers/admin.rb +7 -0
- data/spec/fixture/app/controllers/application.rb +2 -0
- data/spec/fixture/app/controllers/comments.rb +16 -0
- data/spec/fixture/app/controllers/posts.rb +14 -0
- data/spec/fixture/app/models/comment.rb +10 -0
- data/spec/fixture/app/models/post.rb +7 -0
- data/spec/fixture/app/views/admin/show.html.erb +4 -0
- data/spec/fixture/app/views/comments/edit.html.erb +11 -0
- data/spec/fixture/app/views/comments/index.atom.builder +21 -0
- data/spec/fixture/app/views/comments/index.html.erb +15 -0
- data/spec/fixture/app/views/comments/new.html.erb +6 -0
- data/spec/fixture/app/views/layout/application.html.erb +11 -0
- data/spec/fixture/app/views/posts/index.html.erb +7 -0
- data/spec/fixture/app/views/posts/show.html.erb +6 -0
- data/spec/fixture/config/router.rb +11 -0
- data/spec/merb_component_spec.rb +26 -0
- data/spec/posts_spec.rb +173 -0
- data/spec/spec_helper.rb +40 -0
- metadata +112 -0
    
        data/LICENSE
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Copyright (c) 2009 YOUR NAME
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 5 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 6 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 7 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 | 
            +
            the following conditions:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 12 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 17 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 18 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 19 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 20 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README
    ADDED
    
    | @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            merb_component
         | 
| 2 | 
            +
            =============
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Merb plugin that provides composition of controllers.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Example of use:
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              In config/router.rb:
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                resources :posts do |post|
         | 
| 11 | 
            +
                  post.aggregates :comments
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                resource :admin, :controller => :admin do |admin|
         | 
| 14 | 
            +
                  admin.aggregates :comments
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              In controllers:
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                class Posts < Application
         | 
| 20 | 
            +
                  aggregates :comments
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                class Admin < Application
         | 
| 23 | 
            +
                  aggregates :show => :comments
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              In views:
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                Content of the user (id is 2) goes here
         | 
| 28 | 
            +
                <%= component :users, :show, :id => 2 %>
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              For detail, you can see spec/fixture as an example.
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              Enjoy!
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              Genki Takiuchi
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,87 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'rake/gempackagetask'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'merb-core'
         | 
| 5 | 
            +
            require 'merb-core/tasks/merb'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            GEM_NAME = "merb_component"
         | 
| 8 | 
            +
            GEM_VERSION = "0.2.3"
         | 
| 9 | 
            +
            AUTHOR = "Genki Takiuchi"
         | 
| 10 | 
            +
            EMAIL = "genki@s21g.com"
         | 
| 11 | 
            +
            HOMEPAGE = "http://blog.s21g.com/genki"
         | 
| 12 | 
            +
            RUBYFORGE_PROJECT = 'asakusarb'
         | 
| 13 | 
            +
            SUMMARY = "Merb plugin that provides composition of controllers."
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            spec = Gem::Specification.new do |s|
         | 
| 16 | 
            +
              s.rubyforge_project = 'merb'
         | 
| 17 | 
            +
              s.name = GEM_NAME
         | 
| 18 | 
            +
              s.version = GEM_VERSION
         | 
| 19 | 
            +
              s.platform = Gem::Platform::RUBY
         | 
| 20 | 
            +
              s.has_rdoc = true
         | 
| 21 | 
            +
              s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
         | 
| 22 | 
            +
              s.summary = SUMMARY
         | 
| 23 | 
            +
              s.description = s.summary
         | 
| 24 | 
            +
              s.author = AUTHOR
         | 
| 25 | 
            +
              s.email = EMAIL
         | 
| 26 | 
            +
              s.homepage = HOMEPAGE
         | 
| 27 | 
            +
              s.add_dependency('merb', '>= 1.0.7.1')
         | 
| 28 | 
            +
              s.add_development_dependency('merb_full_url', '>= 0.0.2')
         | 
| 29 | 
            +
              s.require_path = 'lib'
         | 
| 30 | 
            +
              s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
            end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Rake::GemPackageTask.new(spec) do |pkg|
         | 
| 35 | 
            +
            	pkg.need_tar = true
         | 
| 36 | 
            +
              pkg.gem_spec = spec
         | 
| 37 | 
            +
            end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            desc "install the plugin as a gem"
         | 
| 40 | 
            +
            task :install do
         | 
| 41 | 
            +
              Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
         | 
| 42 | 
            +
            end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            desc "Uninstall the gem"
         | 
| 45 | 
            +
            task :uninstall do
         | 
| 46 | 
            +
              Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
         | 
| 47 | 
            +
            end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            desc "Create a gemspec file"
         | 
| 50 | 
            +
            task :gemspec do
         | 
| 51 | 
            +
              File.open("#{GEM_NAME}.gemspec", "w") do |file|
         | 
| 52 | 
            +
                file.puts spec.to_ruby
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            desc "Run specs"
         | 
| 57 | 
            +
            task :spec do
         | 
| 58 | 
            +
              sh "spec --color spec"
         | 
| 59 | 
            +
            end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            desc 'Package and upload the release to rubyforge.'
         | 
| 62 | 
            +
            task :release => :package do |t|
         | 
| 63 | 
            +
              require 'rubyforge'
         | 
| 64 | 
            +
            	v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
         | 
| 65 | 
            +
            	abort "Versions don't match #{v} vs #{GEM_VERSION}" unless v == GEM_VERSION
         | 
| 66 | 
            +
            	pkg = "pkg/#{GEM_NAME}-#{GEM_VERSION}"
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            	require 'rubyforge'
         | 
| 69 | 
            +
            	rf = RubyForge.new.configure
         | 
| 70 | 
            +
            	puts "Logging in"
         | 
| 71 | 
            +
            	rf.login
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            	c = rf.userconfig
         | 
| 74 | 
            +
            #	c["release_notes"] = description if description
         | 
| 75 | 
            +
            #	c["release_changes"] = changes if changes
         | 
| 76 | 
            +
            	c["preformatted"] = true
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            	files = [
         | 
| 79 | 
            +
            		"#{pkg}.tgz",
         | 
| 80 | 
            +
            		"#{pkg}.gem"
         | 
| 81 | 
            +
            	].compact
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            	puts "Releasing #{GEM_NAME} v. #{GEM_VERSION}"
         | 
| 84 | 
            +
            	rf.add_release RUBYFORGE_PROJECT, GEM_NAME, GEM_VERSION, *files
         | 
| 85 | 
            +
            end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            task :default => :spec
         | 
    
        data/TODO
    ADDED
    
    
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # make sure we're running inside Merb
         | 
| 2 | 
            +
            if defined?(Merb::Plugins)
         | 
| 3 | 
            +
              # Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in
         | 
| 4 | 
            +
              # your piece of it
         | 
| 5 | 
            +
              Merb::Plugins.config[:merb_component] = {
         | 
| 6 | 
            +
              }
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              Merb::BootLoader.before_app_loads do
         | 
| 9 | 
            +
                # require code that must be loaded before the application
         | 
| 10 | 
            +
                require 'merb_component/controller_ext'
         | 
| 11 | 
            +
                require 'merb_component/resource_ext'
         | 
| 12 | 
            +
                require 'merb_component/router_ext'
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              Merb::BootLoader.after_app_loads do
         | 
| 16 | 
            +
                # code that can be required after the application loads
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
              Merb::Plugins.add_rakefiles "merb_component/merbtasks"
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,217 @@ | |
| 1 | 
            +
            class Merb::Controller
         | 
| 2 | 
            +
              METHOD_TO_ACTION = {
         | 
| 3 | 
            +
                :post => :create,
         | 
| 4 | 
            +
                :put => :update,
         | 
| 5 | 
            +
                :delete => :destroy
         | 
| 6 | 
            +
              }.freeze
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              class << self
         | 
| 9 | 
            +
              private
         | 
| 10 | 
            +
                def is_component(resource = nil)
         | 
| 11 | 
            +
                  resource = controller_name.singular if resource.nil?
         | 
| 12 | 
            +
                  r = resource.to_s
         | 
| 13 | 
            +
                  m = r.camel_case
         | 
| 14 | 
            +
                  iv = proc{|i| "(@#{r} = #{m}.#{i})"}
         | 
| 15 | 
            +
                  ivs = proc{|i| "(@#{r.pluralize} = #{m}.#{i})"}
         | 
| 16 | 
            +
                  class_eval <<-"RUBY"
         | 
| 17 | 
            +
                    def index; display #{ivs["all"]} end
         | 
| 18 | 
            +
                    def show(id) display #{iv["get(id)"]} end
         | 
| 19 | 
            +
                    def new; display #{iv["new"]} end
         | 
| 20 | 
            +
                    def edit(id) display #{iv["get(id)"]}; end
         | 
| 21 | 
            +
                    def create(#{r}) #{iv["create(#{r})"]}; '' end
         | 
| 22 | 
            +
                    def update(id,#{r}) #{iv["get(id)"]}.update_attributes(#{r}); '' end
         | 
| 23 | 
            +
                    def destroy(id) #{iv["get(id)"]}.destroy; '' end
         | 
| 24 | 
            +
                  RUBY
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def aggregates(aggregation, options = {})
         | 
| 28 | 
            +
                  if aggregation.is_a?(Symbol)
         | 
| 29 | 
            +
                    aggregation = {:show => aggregation}
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                  aggregation.each do |agg_action, arg|
         | 
| 32 | 
            +
                    define_method(arg){} unless method_defined?(arg)
         | 
| 33 | 
            +
                    model = Object.full_const_get(arg.to_s.singular.camel_case)
         | 
| 34 | 
            +
                    key = "#{controller_name.singular}_id"
         | 
| 35 | 
            +
                    var = "@#{arg.to_s.singular}"
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    add_filter(_before_filters, proc{|c|
         | 
| 38 | 
            +
                      id = params.delete(key)
         | 
| 39 | 
            +
                      method = request.method
         | 
| 40 | 
            +
                      scope = Mash.new
         | 
| 41 | 
            +
                      scope[key] = id if id
         | 
| 42 | 
            +
                      object = nil
         | 
| 43 | 
            +
                      if action = METHOD_TO_ACTION[method]
         | 
| 44 | 
            +
                        # setup request
         | 
| 45 | 
            +
                        req = request.dup
         | 
| 46 | 
            +
                        req.reset_params!
         | 
| 47 | 
            +
                        req.instance_variable_set(:@params,
         | 
| 48 | 
            +
                          params.merge(:controller => arg, :action => action))
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                        # call action of subsidiary controller with scope
         | 
| 51 | 
            +
                        cc = Object.full_const_get(params[:action].camel_case).new(req)
         | 
| 52 | 
            +
                        model.send :with_scope, scope do
         | 
| 53 | 
            +
                          begin
         | 
| 54 | 
            +
                            layout = cc.class.default_layout
         | 
| 55 | 
            +
                            cc.class.layout(options[:layout])
         | 
| 56 | 
            +
                            cc._abstract_dispatch(action)
         | 
| 57 | 
            +
                          ensure
         | 
| 58 | 
            +
                            cc.class.layout(layout)
         | 
| 59 | 
            +
                          end
         | 
| 60 | 
            +
                          object = cc.instance_variable_get(var)
         | 
| 61 | 
            +
                          throw(:halt, proc{
         | 
| 62 | 
            +
                            target = controller_name.singular.intern
         | 
| 63 | 
            +
                            target = object.send(target) if object.respond_to?(target)
         | 
| 64 | 
            +
                            redirect resource(target)
         | 
| 65 | 
            +
                          }) if object.errors.empty?
         | 
| 66 | 
            +
                          c.instance_variable_set(var, object)
         | 
| 67 | 
            +
                        end
         | 
| 68 | 
            +
                      elsif params[:id]
         | 
| 69 | 
            +
                        # GET with component id
         | 
| 70 | 
            +
                        object = model.get(params[:id])
         | 
| 71 | 
            +
                        c.instance_variable_set(var, object)
         | 
| 72 | 
            +
                      elsif params[:format]
         | 
| 73 | 
            +
                        @component_format = params.delete(:format)
         | 
| 74 | 
            +
                        #c._abstract_dispatch(action)
         | 
| 75 | 
            +
                      end
         | 
| 76 | 
            +
                      c.instance_variable_set("#{var}_component", object)
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                      # prepare for performing actoin of principal controller
         | 
| 79 | 
            +
                      c.params[:id] = id if id
         | 
| 80 | 
            +
                      c.params[:action] = c.action_name = agg_action.to_s
         | 
| 81 | 
            +
                    }, :only => arg)
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    add_filter(_after_filters, proc{|c|
         | 
| 84 | 
            +
                      # setup request
         | 
| 85 | 
            +
                      request.reset_params!
         | 
| 86 | 
            +
                      request.instance_variable_set(:@params, params.merge(
         | 
| 87 | 
            +
                        :controller => arg, :action => :index,
         | 
| 88 | 
            +
                        :format => @component_format))
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                      # call index action of subsidiary controller with scope
         | 
| 91 | 
            +
                      cc = Object.full_const_get(arg.to_s.camel_case).new(request)
         | 
| 92 | 
            +
                      @body = Aggregator.new(c, cc.class) do
         | 
| 93 | 
            +
                        cc._abstract_dispatch(:index)
         | 
| 94 | 
            +
                      end.result
         | 
| 95 | 
            +
                    }, :only => agg_action, :if => proc{@component_format})
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              class Aggregator
         | 
| 101 | 
            +
                attr_reader :controller, :object, :result, :context
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                def initialize(context, controller, &block)
         | 
| 104 | 
            +
                  @context = context
         | 
| 105 | 
            +
                  @controller = controller
         | 
| 106 | 
            +
                  @agg_name = @context.controller_name.singular.intern
         | 
| 107 | 
            +
                  model_class = Object.full_const_get(controller.name.singular)
         | 
| 108 | 
            +
                  @object = @context.instance_variable_get("@#{@agg_name}")
         | 
| 109 | 
            +
                  @scope = {}
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  relationship = model_class.relationships[@agg_name]
         | 
| 112 | 
            +
                  if @object && relationship
         | 
| 113 | 
            +
                    Merb.logger.debug [model_class, @agg_name].inspect
         | 
| 114 | 
            +
                    key_names = relationship.child_key.map{|i| i.name}
         | 
| 115 | 
            +
                    @scope = Hash[key_names.zip(@object.key)] if @object
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  @result = begin
         | 
| 119 | 
            +
                    aggregators = Thread::current[:aggregators] ||= {}
         | 
| 120 | 
            +
                    (aggregators[controller] ||= []).push(self)
         | 
| 121 | 
            +
                    if model_class.respond_to?(:with_scope)
         | 
| 122 | 
            +
                      model_class.send(:with_scope, @scope, &block)
         | 
| 123 | 
            +
                    else
         | 
| 124 | 
            +
                      block.call
         | 
| 125 | 
            +
                    end
         | 
| 126 | 
            +
                  ensure
         | 
| 127 | 
            +
                    aggregators[controller].pop
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                def key
         | 
| 132 | 
            +
                  @object || @agg_name
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              def _abstract_dispatch(*args)
         | 
| 137 | 
            +
                _dispatch = Merb::AbstractController.instance_method(:_dispatch)
         | 
| 138 | 
            +
                _dispatch.bind(self).call(*args)
         | 
| 139 | 
            +
              end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
              def aggregator
         | 
| 142 | 
            +
                aggregators = Thread::current[:aggregators] ||= {}
         | 
| 143 | 
            +
                (aggregators[self.class] ||= []).last
         | 
| 144 | 
            +
              end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
              def url_with_scope(*args)
         | 
| 147 | 
            +
                result = url_without_scope(*args)
         | 
| 148 | 
            +
                if (agg = aggregator) && (key = agg.key)
         | 
| 149 | 
            +
                  resource_without_scope(key) + result
         | 
| 150 | 
            +
                else
         | 
| 151 | 
            +
                  result
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
              end
         | 
| 154 | 
            +
              alias_method :url_without_scope, :url
         | 
| 155 | 
            +
              alias_method :url, :url_with_scope
         | 
| 156 | 
            +
             | 
| 157 | 
            +
            private
         | 
| 158 | 
            +
              def component(controller, action, params = {})
         | 
| 159 | 
            +
                params = self.params.merge(
         | 
| 160 | 
            +
                  :controller => controller, :action => action
         | 
| 161 | 
            +
                ).merge(params)
         | 
| 162 | 
            +
                var = "@#{controller.to_s.singular}"
         | 
| 163 | 
            +
                object = instance_variable_get("#{var}_component")
         | 
| 164 | 
            +
                controller = Object.full_const_get(controller.to_s.camel_case)
         | 
| 165 | 
            +
                req = request.dup
         | 
| 166 | 
            +
                req.reset_params!
         | 
| 167 | 
            +
                req.instance_variable_set :@params, params
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                Aggregator.new(this = self, controller) do
         | 
| 170 | 
            +
                  controller.new(req)._dispatch(action).instance_eval do
         | 
| 171 | 
            +
                    if object
         | 
| 172 | 
            +
                      original = instance_variable_get(var)
         | 
| 173 | 
            +
                      object.attributes = original.attributes if original
         | 
| 174 | 
            +
                      instance_variable_set(var, object)
         | 
| 175 | 
            +
                    end
         | 
| 176 | 
            +
                    cc = this.instance_variable_get(:@_caught_content)
         | 
| 177 | 
            +
                    instance_variable_get(:@_caught_content).each do |k, v|
         | 
| 178 | 
            +
                      next if k == :for_layout
         | 
| 179 | 
            +
                      cc[k].nil? ? this.throw_content(k, v) : this.append_content(k, v)
         | 
| 180 | 
            +
                    end
         | 
| 181 | 
            +
                    render :layout => false
         | 
| 182 | 
            +
                  end
         | 
| 183 | 
            +
                end.result
         | 
| 184 | 
            +
              end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
              def form_for_component(controller, params = {}, &block)
         | 
| 187 | 
            +
                var = "@#{controller.to_s.singular}"
         | 
| 188 | 
            +
                object = instance_variable_get(var)
         | 
| 189 | 
            +
                return nil if object.nil?
         | 
| 190 | 
            +
                object = instance_variable_get("#{var}_component") || object
         | 
| 191 | 
            +
                if object.new_record?
         | 
| 192 | 
            +
                  component(controller, :new, params)
         | 
| 193 | 
            +
                else
         | 
| 194 | 
            +
                  component(controller, :edit, {:id => object.id}.merge(params))
         | 
| 195 | 
            +
                end
         | 
| 196 | 
            +
              end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
              def resource_with_scope(first, *args)
         | 
| 199 | 
            +
                agg = aggregator
         | 
| 200 | 
            +
                return resource_without_scope(first, *args) unless agg
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                controller = case first
         | 
| 203 | 
            +
                when Symbol, String
         | 
| 204 | 
            +
                  Object.full_const_get(first.to_s.camel_case)
         | 
| 205 | 
            +
                else
         | 
| 206 | 
            +
                  Object.full_const_get(first.class.to_s.pluralize.camel_case)
         | 
| 207 | 
            +
                end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                if controller <=> agg.controller && agg.key
         | 
| 210 | 
            +
                  resource_without_scope(agg.key, first, *args)
         | 
| 211 | 
            +
                else
         | 
| 212 | 
            +
                  resource_without_scope(first, *args)
         | 
| 213 | 
            +
                end
         | 
| 214 | 
            +
              end
         | 
| 215 | 
            +
              alias_method :resource_without_scope, :resource
         | 
| 216 | 
            +
              alias_method :resource, :resource_with_scope
         | 
| 217 | 
            +
            end
         | 
    
        data/spec/admin_spec.rb
    ADDED
    
    | @@ -0,0 +1,106 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Admin do
         | 
| 4 | 
            +
              before do
         | 
| 5 | 
            +
                @req = Merb::Request.new(
         | 
| 6 | 
            +
                  Merb::Const::REQUEST_PATH => "/admin",
         | 
| 7 | 
            +
                  Merb::Const::REQUEST_METHOD => "GET",
         | 
| 8 | 
            +
                  Merb::Const::QUERY_STRING => "")
         | 
| 9 | 
            +
                @c = Admin.new(@req)
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              it "should be a controller" do
         | 
| 13 | 
            +
                @c.should be_kind_of(Merb::Controller)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            describe "Admin controller" do
         | 
| 18 | 
            +
              before :all do
         | 
| 19 | 
            +
                @post = Post.create
         | 
| 20 | 
            +
                @comment = @post.comments.create(:body => "test")
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              it "should be tested on at least one post and comment" do
         | 
| 24 | 
            +
                Post.count.should > 0
         | 
| 25 | 
            +
                Comment.count.should > 0
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              it "should show index html" do
         | 
| 29 | 
            +
                res = request(resource(:admin))
         | 
| 30 | 
            +
                res.should be_successful
         | 
| 31 | 
            +
                res.should have_xpath("//h1")
         | 
| 32 | 
            +
                res.should have_xpath("//h2")
         | 
| 33 | 
            +
                res.should have_xpath("//ul/li")
         | 
| 34 | 
            +
                res.should_not have_xpath("//form")
         | 
| 35 | 
            +
                res.should have_xpath("//a[@href='/admin/comments?page=1']")
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              it "should show index html for pagination params" do
         | 
| 39 | 
            +
                res = request("/admin/comments?page=2")
         | 
| 40 | 
            +
                res.should be_successful
         | 
| 41 | 
            +
                res.should have_xpath("//h1")
         | 
| 42 | 
            +
                res.should have_xpath("//h2")
         | 
| 43 | 
            +
                res.should have_xpath("//ul")
         | 
| 44 | 
            +
                res.should_not have_xpath("//form")
         | 
| 45 | 
            +
                res.should have_xpath("//a[@href='/admin/comments?page=3']")
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              it "should show html after update a comment" do
         | 
| 49 | 
            +
                comment = @post.comments.last
         | 
| 50 | 
            +
                comment.should be_kind_of(Comment)
         | 
| 51 | 
            +
                res = request(resource(:admin, comment),
         | 
| 52 | 
            +
                  :method => 'PUT', :params => {:comment => {:body => "bar"}})
         | 
| 53 | 
            +
                res.should redirect_to("/admin")
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                res = request(res.headers["Location"])
         | 
| 56 | 
            +
                res.should be_successful
         | 
| 57 | 
            +
                res.should have_xpath("//h1")
         | 
| 58 | 
            +
                res.should have_xpath("//h2")
         | 
| 59 | 
            +
                res.should have_xpath("//ul/li[1]")
         | 
| 60 | 
            +
                res.should_not have_xpath("//form")
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              it "should show html after failed to update a comment" do
         | 
| 64 | 
            +
                comment = @post.comments.last
         | 
| 65 | 
            +
                comment.should be_kind_of(Comment)
         | 
| 66 | 
            +
                res = request(resource(:admin, comment),
         | 
| 67 | 
            +
                  :method => 'PUT', :params => {:comment => {:body => ""}})
         | 
| 68 | 
            +
                res.should be_successful
         | 
| 69 | 
            +
                res.should have_xpath("//h1")
         | 
| 70 | 
            +
                res.should have_xpath("//h2")
         | 
| 71 | 
            +
                res.should have_xpath("//ul/li[1]")
         | 
| 72 | 
            +
                res.should have_xpath("//form[@action='/admin/comments/#{comment.id}']")
         | 
| 73 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 74 | 
            +
                res.should have_xpath("//input[@value='put']")
         | 
| 75 | 
            +
                res.should have_tag("div.error")
         | 
| 76 | 
            +
                res.should have_tag("input.error[@name='comment[body]']")
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              it "should show html after delete a comment" do
         | 
| 80 | 
            +
                count = @post.comments.count
         | 
| 81 | 
            +
                comment = @post.comments.last
         | 
| 82 | 
            +
                comment.should be_kind_of(Comment)
         | 
| 83 | 
            +
                res = request(resource(:admin, comment), :method => 'DELETE')
         | 
| 84 | 
            +
                res.should redirect_to("/admin")
         | 
| 85 | 
            +
                
         | 
| 86 | 
            +
                res = request(res.headers["Location"])
         | 
| 87 | 
            +
                res.should be_successful
         | 
| 88 | 
            +
                res.should have_xpath("//h1")
         | 
| 89 | 
            +
                res.should have_xpath("//h2")
         | 
| 90 | 
            +
                res.should_not have_xpath("//form")
         | 
| 91 | 
            +
                @post.comments.count.should == count - 1
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
              it "should show html after show a comment" do
         | 
| 95 | 
            +
                comment = @post.comments.create(:body => "hello")
         | 
| 96 | 
            +
                comment.should_not be_new_record
         | 
| 97 | 
            +
                res = request(resource(:admin, comment), :method => 'GET')
         | 
| 98 | 
            +
                res.should be_successful
         | 
| 99 | 
            +
                res.should have_xpath("//h1")
         | 
| 100 | 
            +
                res.should have_xpath("//h2")
         | 
| 101 | 
            +
                res.should have_xpath("//form[@action='/admin/comments/#{comment.id}']")
         | 
| 102 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 103 | 
            +
                res.should have_xpath("//input[@value='put']")
         | 
| 104 | 
            +
                res.should_not have_xpath("//body/meta")
         | 
| 105 | 
            +
              end
         | 
| 106 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            class Comments < Application
         | 
| 2 | 
            +
              is_component :comment
         | 
| 3 | 
            +
              provides :atom, :only => :index
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def new
         | 
| 6 | 
            +
                @comment = Comment.new
         | 
| 7 | 
            +
                @comment.body = "new"
         | 
| 8 | 
            +
                display @comment
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              def edit(id)
         | 
| 12 | 
            +
                @comment = Comment.get(id)
         | 
| 13 | 
            +
                @comment.body = "edit"
         | 
| 14 | 
            +
                display @comment
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            <h3>
         | 
| 2 | 
            +
              Edit Comment of 
         | 
| 3 | 
            +
              <%= link_to h(@comment.post.id), resource(@comment.post) %>
         | 
| 4 | 
            +
            </h3>
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            <%= error_messages_for @comment %>
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            <%= form_for @comment, :action => resource(@comment), :method => :put do %>
         | 
| 9 | 
            +
              <%= text_field :body %>
         | 
| 10 | 
            +
              <%= submit "Submit" %>
         | 
| 11 | 
            +
            <% end =%>
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            xml.instruct! :xml, :version=>"1.0" 
         | 
| 2 | 
            +
            xml.feed(:xmlns => "http://www.w3.org/2005/Atom") do |feed|
         | 
| 3 | 
            +
              feed.title @title
         | 
| 4 | 
            +
              feed.link :type => 'text/html', :rel => 'alternate',
         | 
| 5 | 
            +
                :href => full_resource(:comments)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              @comments.each do |comment|
         | 
| 8 | 
            +
                feed.entry do |entry|
         | 
| 9 | 
            +
                  entry.id comment.id
         | 
| 10 | 
            +
                  entry.title "Comment to post#%s" % comment.post.id
         | 
| 11 | 
            +
                  entry.content comment.body, :type => 'text'
         | 
| 12 | 
            +
                  #entry.issued comment.created_at
         | 
| 13 | 
            +
                  #entry.modified comment.updated_at
         | 
| 14 | 
            +
                  entry.link :type => "text/html", :rel => "alternate",
         | 
| 15 | 
            +
                    :href => full_resource(comment)
         | 
| 16 | 
            +
                  #entry.author do |author|
         | 
| 17 | 
            +
                  #  author.name comment.user.login
         | 
| 18 | 
            +
                  #end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            <h2>Comments</h2>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <ul>
         | 
| 4 | 
            +
            <% @comments.each do |comment| %>
         | 
| 5 | 
            +
              <li>
         | 
| 6 | 
            +
                <%= link_to h(comment.body), resource(comment) %>
         | 
| 7 | 
            +
              </li>
         | 
| 8 | 
            +
            <% end %>
         | 
| 9 | 
            +
            </ul>
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            <%= link_to "next", url(:page => params[:page].to_i + 1) %>
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            <% throw_content :for_post do %>
         | 
| 14 | 
            +
              test_content
         | 
| 15 | 
            +
            <% end %>
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
         | 
| 2 | 
            +
            <html xmlns="http://www.w3.org/1999/xhtml"
         | 
| 3 | 
            +
             xmlns:v="urn:schemas-microsoft-com:vml" xml:lang="en-us" lang="en-us">
         | 
| 4 | 
            +
            <head>
         | 
| 5 | 
            +
              <title>merb_component</title>
         | 
| 6 | 
            +
              <meta http-equiv="content-type" content="text/html; charset=utf-8" />
         | 
| 7 | 
            +
            </head>
         | 
| 8 | 
            +
            <body>
         | 
| 9 | 
            +
              <%= catch_content :for_layout %>
         | 
| 10 | 
            +
            </body>
         | 
| 11 | 
            +
            </html>
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe "merb_component" do
         | 
| 4 | 
            +
              it "should extend controller" do
         | 
| 5 | 
            +
                Posts.private_instance_methods.should be_include("component")
         | 
| 6 | 
            +
                Posts.private_instance_methods.should be_include("form_for_component")
         | 
| 7 | 
            +
                Posts.instance_methods.should be_include("aggregator")
         | 
| 8 | 
            +
                Posts.private_instance_methods.should be_include("resource")
         | 
| 9 | 
            +
                Posts.public_instance_methods.should be_include("url")
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              it "should not extend model" do
         | 
| 13 | 
            +
                Post.public_methods.should_not be_include("related_with")
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              it "should accept symbol as the first param of compoent" do
         | 
| 17 | 
            +
                req = Merb::Request.new({})
         | 
| 18 | 
            +
                c = Posts.new(req)
         | 
| 19 | 
            +
                proc do
         | 
| 20 | 
            +
                  c.send(:component, :comments, :index)
         | 
| 21 | 
            +
                end.should raise_error(Merb::Router::GenerationError)
         | 
| 22 | 
            +
                c.instance_variable_set(:@post, Post.create)
         | 
| 23 | 
            +
                result = c.send(:component, :comments, :index)
         | 
| 24 | 
            +
                result.should be_kind_of(String)
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
    
        data/spec/posts_spec.rb
    ADDED
    
    | @@ -0,0 +1,173 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Posts do
         | 
| 4 | 
            +
              before do
         | 
| 5 | 
            +
                @req = Merb::Request.new(
         | 
| 6 | 
            +
                  Merb::Const::REQUEST_PATH => "/posts",
         | 
| 7 | 
            +
                  Merb::Const::REQUEST_METHOD => "GET",
         | 
| 8 | 
            +
                  Merb::Const::QUERY_STRING => "")
         | 
| 9 | 
            +
                @c = Posts.new(@req)
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              it "should be a controller" do
         | 
| 13 | 
            +
                @c.should be_kind_of(Merb::Controller)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            describe "Posts controller" do
         | 
| 18 | 
            +
              before :all do
         | 
| 19 | 
            +
                @post = Post.create
         | 
| 20 | 
            +
                @comment = @post.comments.create(:body => "test")
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              it "should be tested on at least one post" do
         | 
| 24 | 
            +
                Post.count.should > 0
         | 
| 25 | 
            +
                Comment.count.should > 0
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              it "should show html" do
         | 
| 29 | 
            +
                res = request(resource(@post))
         | 
| 30 | 
            +
                res.should be_successful
         | 
| 31 | 
            +
                res.should have_xpath("//h1")
         | 
| 32 | 
            +
                res.should have_xpath("//h2")
         | 
| 33 | 
            +
                res.should have_xpath("//ul/li")
         | 
| 34 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 35 | 
            +
                res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
         | 
| 36 | 
            +
                res.should_not have_xpath("//input[@value='put']")
         | 
| 37 | 
            +
                res.should have_xpath("//input[@value='new']")
         | 
| 38 | 
            +
                res.should have_xpath("//a[@href='/posts/#{@post.id}/comments?page=1']")
         | 
| 39 | 
            +
                res.should contain("test_content")
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              it "should show html for pagination params" do
         | 
| 43 | 
            +
                res = request("/posts/#{@post.id}/comments?page=2")
         | 
| 44 | 
            +
                res.should be_successful
         | 
| 45 | 
            +
                res.should have_xpath("//h1")
         | 
| 46 | 
            +
                res.should have_xpath("//h2")
         | 
| 47 | 
            +
                res.should have_xpath("//ul/li")
         | 
| 48 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 49 | 
            +
                res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
         | 
| 50 | 
            +
                res.should_not have_xpath("//input[@value='put']")
         | 
| 51 | 
            +
                res.should have_xpath("//input[@value='new']")
         | 
| 52 | 
            +
                res.should have_xpath("//a[@href='/posts/#{@post.id}/comments?page=3']")
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              it "should show html after post a comment" do
         | 
| 56 | 
            +
                count = @post.comments.count
         | 
| 57 | 
            +
                res = request(resource(@post, :comments),
         | 
| 58 | 
            +
                  :method => 'POST', :params => {:comment => {:body => "foo"}})
         | 
| 59 | 
            +
                res.should redirect_to("/posts/#{@post.id}")
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                res = request(res.headers["Location"])
         | 
| 62 | 
            +
                res.should be_successful
         | 
| 63 | 
            +
                res.should have_xpath("//h1")
         | 
| 64 | 
            +
                res.should have_xpath("//h2")
         | 
| 65 | 
            +
                res.should have_xpath("//ul/li[1]")
         | 
| 66 | 
            +
                res.should have_xpath("//ul/li[2]")
         | 
| 67 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 68 | 
            +
                res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
         | 
| 69 | 
            +
                res.should_not have_xpath("//input[@value='put']")
         | 
| 70 | 
            +
                res.should contain("foo")
         | 
| 71 | 
            +
                Comment.all(:post_id => @post.id).count.should == count + 1
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              it "should show html after failed to post a comment" do
         | 
| 75 | 
            +
                count = Comment.all(:post_id => @post.id).count
         | 
| 76 | 
            +
                res = request(resource(@post, :comments),
         | 
| 77 | 
            +
                  :method => 'POST', :params => {:comment => {:body => ""}})
         | 
| 78 | 
            +
                res.should be_successful
         | 
| 79 | 
            +
                res.should have_xpath("//h1")
         | 
| 80 | 
            +
                res.should have_xpath("//h2")
         | 
| 81 | 
            +
                res.should have_xpath("//ul/li[1]")
         | 
| 82 | 
            +
                res.should have_xpath("//ul/li[2]")
         | 
| 83 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 84 | 
            +
                res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
         | 
| 85 | 
            +
                res.should_not have_xpath("//input[@value='put']")
         | 
| 86 | 
            +
                res.should have_tag("div.error")
         | 
| 87 | 
            +
                res.should have_tag("input.error[@name='comment[body]']")
         | 
| 88 | 
            +
                Comment.all(:post_id => @post.id).count.should == count
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              it "should show html after update a comment" do
         | 
| 92 | 
            +
                comment = @post.comments.last
         | 
| 93 | 
            +
                comment.should be_kind_of(Comment)
         | 
| 94 | 
            +
                res = request(resource(@post, comment),
         | 
| 95 | 
            +
                  :method => 'PUT', :params => {:comment => {:body => "bar"}})
         | 
| 96 | 
            +
                res.should redirect_to("/posts/#{@post.id}")
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                res = request(res.headers["Location"])
         | 
| 99 | 
            +
                res.should be_successful
         | 
| 100 | 
            +
                res.should have_xpath("//h1")
         | 
| 101 | 
            +
                res.should have_xpath("//h2")
         | 
| 102 | 
            +
                res.should have_xpath("//ul/li[1]")
         | 
| 103 | 
            +
                res.should have_xpath("//ul/li[2]")
         | 
| 104 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 105 | 
            +
                res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
         | 
| 106 | 
            +
                res.should_not have_xpath("//input[@value='put']")
         | 
| 107 | 
            +
                res.should contain("bar")
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
              it "should show html after failed to update a comment" do
         | 
| 111 | 
            +
                comment = @post.comments.last
         | 
| 112 | 
            +
                comment.should be_kind_of(Comment)
         | 
| 113 | 
            +
                res = request(resource(@post, comment),
         | 
| 114 | 
            +
                  :method => 'PUT', :params => {:comment => {:body => ""}})
         | 
| 115 | 
            +
                res.should be_successful
         | 
| 116 | 
            +
                res.should have_xpath("//h1")
         | 
| 117 | 
            +
                res.should have_xpath("//h2")
         | 
| 118 | 
            +
                res.should have_xpath("//ul/li[1]")
         | 
| 119 | 
            +
                res.should have_xpath("//ul/li[2]")
         | 
| 120 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 121 | 
            +
                url = "/posts/#{@post.id}/comments/#{comment.id}"
         | 
| 122 | 
            +
                res.should have_xpath("//form[@action='#{url}']")
         | 
| 123 | 
            +
                res.should have_xpath("//input[@value='put']")
         | 
| 124 | 
            +
                res.should have_tag("div.error")
         | 
| 125 | 
            +
                res.should have_tag("input.error[@name='comment[body]']")
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              it "should show html after delete a comment" do
         | 
| 129 | 
            +
                count = @post.comments.count
         | 
| 130 | 
            +
                comment = @post.comments.last
         | 
| 131 | 
            +
                comment.should be_kind_of(Comment)
         | 
| 132 | 
            +
                res = request(resource(@post, comment), :method => 'DELETE')
         | 
| 133 | 
            +
                res.should redirect_to("/posts/#{@post.id}")
         | 
| 134 | 
            +
                
         | 
| 135 | 
            +
                res = request(res.headers["Location"])
         | 
| 136 | 
            +
                res.should be_successful
         | 
| 137 | 
            +
                res.should have_xpath("//h1")
         | 
| 138 | 
            +
                res.should have_xpath("//h2")
         | 
| 139 | 
            +
                res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
         | 
| 140 | 
            +
                res.should have_xpath("//form[@method='post']")
         | 
| 141 | 
            +
                res.should_not have_xpath("//input[@value='put']")
         | 
| 142 | 
            +
                @post.comments.count.should == count - 1
         | 
| 143 | 
            +
              end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
              it "should show html after show a comment" do
         | 
| 146 | 
            +
                comment = @post.comments.create(:body => "test")
         | 
| 147 | 
            +
                comment.should_not be_new_record
         | 
| 148 | 
            +
                res = request(resource(@post, comment), :method => 'GET')
         | 
| 149 | 
            +
                res.should be_successful
         | 
| 150 | 
            +
                res.should have_xpath("//h1")
         | 
| 151 | 
            +
                res.should have_xpath("//h2")
         | 
| 152 | 
            +
                url = "/posts/#{@post.id}/comments/#{comment.id}"
         | 
| 153 | 
            +
                res.should have_xpath("//form[@action='#{url}']")
         | 
| 154 | 
            +
                res.should have_xpath("//input[@value='put']")
         | 
| 155 | 
            +
                res.should_not have_xpath("//body/meta")
         | 
| 156 | 
            +
                res.should have_xpath("//input[@value='edit']")
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                pending "should check pagination"
         | 
| 159 | 
            +
              end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
              it "should provide atom feed for comments" do
         | 
| 162 | 
            +
                comment = @post.comments.create(:body => "test")
         | 
| 163 | 
            +
                comment.should_not be_new_record
         | 
| 164 | 
            +
                res = request(resource(@post, :comments, :format => :atom))
         | 
| 165 | 
            +
                res.should be_successful
         | 
| 166 | 
            +
                res.should have_xpath("//feed/title")
         | 
| 167 | 
            +
                url = "http://example.org/posts/#{@post.id}/comments"
         | 
| 168 | 
            +
                res.should have_xpath("//feed/link[@href='#{url}']")
         | 
| 169 | 
            +
                res.should have_xpath("//entry/title")
         | 
| 170 | 
            +
                url = "http://example.org/posts/#{@post.id}/comments/#{comment.id}"
         | 
| 171 | 
            +
                res.should have_xpath("//entry/link[@href='#{url}']")
         | 
| 172 | 
            +
              end
         | 
| 173 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            $:.push File.join(File.dirname(__FILE__), '..', 'lib')
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'rubygems'
         | 
| 4 | 
            +
            require 'merb-core'
         | 
| 5 | 
            +
            require 'merb-core/plugins'
         | 
| 6 | 
            +
            require 'merb_component'
         | 
| 7 | 
            +
            require "spec" # Satisfies Autotest and anyone else not using the Rake tasks
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            dependency "dm-core"
         | 
| 10 | 
            +
            dependency "dm-aggregates"
         | 
| 11 | 
            +
            dependency "merb-action-args"
         | 
| 12 | 
            +
            dependency "merb-helpers"
         | 
| 13 | 
            +
            dependency "merb-assets"
         | 
| 14 | 
            +
            dependency "dm-validations"
         | 
| 15 | 
            +
            dependency "merb-builder"
         | 
| 16 | 
            +
            dependency "merb_full_url"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            use_orm :datamapper
         | 
| 19 | 
            +
            use_test :rspec
         | 
| 20 | 
            +
            use_template_engine :erb
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            # this loads all plugins required in your init file so don't add them
         | 
| 23 | 
            +
            # here again, Merb will do it for you
         | 
| 24 | 
            +
            Merb.disable(:initfile)
         | 
| 25 | 
            +
            Merb.start_environment(
         | 
| 26 | 
            +
              :testing      => true,
         | 
| 27 | 
            +
              :adapter      => 'runner',
         | 
| 28 | 
            +
              :environment  => ENV['MERB_ENV'] || 'test',
         | 
| 29 | 
            +
              :merb_root    => File.dirname(__FILE__) / 'fixture',
         | 
| 30 | 
            +
              :log_file     => File.dirname(__FILE__) / '..' / "merb_test.log"
         | 
| 31 | 
            +
            )
         | 
| 32 | 
            +
            DataMapper.setup(:default, "sqlite3::memory:")
         | 
| 33 | 
            +
            Merb.add_mime_type(:atom, :to_atom, %w[application/atom+xml])
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            Spec::Runner.configure do |config|
         | 
| 36 | 
            +
              config.include(Merb::Test::ViewHelper)
         | 
| 37 | 
            +
              config.include(Merb::Test::RouteHelper)
         | 
| 38 | 
            +
              config.include(Merb::Test::ControllerHelper)
         | 
| 39 | 
            +
              config.before(:all){DataMapper.auto_migrate!}
         | 
| 40 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,112 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: merb_component
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              version: 0.2.3
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors: 
         | 
| 7 | 
            +
            - Genki Takiuchi
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            date: 2009-03-27 00:00:00 +09:00
         | 
| 13 | 
            +
            default_executable: 
         | 
| 14 | 
            +
            dependencies: 
         | 
| 15 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 16 | 
            +
              name: merb
         | 
| 17 | 
            +
              type: :runtime
         | 
| 18 | 
            +
              version_requirement: 
         | 
| 19 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 20 | 
            +
                requirements: 
         | 
| 21 | 
            +
                - - ">="
         | 
| 22 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 23 | 
            +
                    version: 1.0.7.1
         | 
| 24 | 
            +
                version: 
         | 
| 25 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 26 | 
            +
              name: merb_full_url
         | 
| 27 | 
            +
              type: :development
         | 
| 28 | 
            +
              version_requirement: 
         | 
| 29 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 30 | 
            +
                requirements: 
         | 
| 31 | 
            +
                - - ">="
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 33 | 
            +
                    version: 0.0.2
         | 
| 34 | 
            +
                version: 
         | 
| 35 | 
            +
            description: Merb plugin that provides composition of controllers.
         | 
| 36 | 
            +
            email: genki@s21g.com
         | 
| 37 | 
            +
            executables: []
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            extensions: []
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            extra_rdoc_files: 
         | 
| 42 | 
            +
            - README
         | 
| 43 | 
            +
            - LICENSE
         | 
| 44 | 
            +
            - TODO
         | 
| 45 | 
            +
            files: 
         | 
| 46 | 
            +
            - LICENSE
         | 
| 47 | 
            +
            - README
         | 
| 48 | 
            +
            - Rakefile
         | 
| 49 | 
            +
            - TODO
         | 
| 50 | 
            +
            - lib/merb_component
         | 
| 51 | 
            +
            - lib/merb_component/controller_ext.rb
         | 
| 52 | 
            +
            - lib/merb_component/merbtasks.rb
         | 
| 53 | 
            +
            - lib/merb_component/resource_ext.rb
         | 
| 54 | 
            +
            - lib/merb_component/router_ext.rb
         | 
| 55 | 
            +
            - lib/merb_component.rb
         | 
| 56 | 
            +
            - spec/admin_spec.rb
         | 
| 57 | 
            +
            - spec/fixture
         | 
| 58 | 
            +
            - spec/fixture/app
         | 
| 59 | 
            +
            - spec/fixture/app/controllers
         | 
| 60 | 
            +
            - spec/fixture/app/controllers/admin.rb
         | 
| 61 | 
            +
            - spec/fixture/app/controllers/application.rb
         | 
| 62 | 
            +
            - spec/fixture/app/controllers/comments.rb
         | 
| 63 | 
            +
            - spec/fixture/app/controllers/posts.rb
         | 
| 64 | 
            +
            - spec/fixture/app/models
         | 
| 65 | 
            +
            - spec/fixture/app/models/comment.rb
         | 
| 66 | 
            +
            - spec/fixture/app/models/post.rb
         | 
| 67 | 
            +
            - spec/fixture/app/views
         | 
| 68 | 
            +
            - spec/fixture/app/views/admin
         | 
| 69 | 
            +
            - spec/fixture/app/views/admin/show.html.erb
         | 
| 70 | 
            +
            - spec/fixture/app/views/comments
         | 
| 71 | 
            +
            - spec/fixture/app/views/comments/edit.html.erb
         | 
| 72 | 
            +
            - spec/fixture/app/views/comments/index.atom.builder
         | 
| 73 | 
            +
            - spec/fixture/app/views/comments/index.html.erb
         | 
| 74 | 
            +
            - spec/fixture/app/views/comments/new.html.erb
         | 
| 75 | 
            +
            - spec/fixture/app/views/layout
         | 
| 76 | 
            +
            - spec/fixture/app/views/layout/application.html.erb
         | 
| 77 | 
            +
            - spec/fixture/app/views/posts
         | 
| 78 | 
            +
            - spec/fixture/app/views/posts/index.html.erb
         | 
| 79 | 
            +
            - spec/fixture/app/views/posts/show.html.erb
         | 
| 80 | 
            +
            - spec/fixture/config
         | 
| 81 | 
            +
            - spec/fixture/config/router.rb
         | 
| 82 | 
            +
            - spec/merb_component_spec.rb
         | 
| 83 | 
            +
            - spec/posts_spec.rb
         | 
| 84 | 
            +
            - spec/spec_helper.rb
         | 
| 85 | 
            +
            has_rdoc: true
         | 
| 86 | 
            +
            homepage: http://blog.s21g.com/genki
         | 
| 87 | 
            +
            post_install_message: 
         | 
| 88 | 
            +
            rdoc_options: []
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            require_paths: 
         | 
| 91 | 
            +
            - lib
         | 
| 92 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 93 | 
            +
              requirements: 
         | 
| 94 | 
            +
              - - ">="
         | 
| 95 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 96 | 
            +
                  version: "0"
         | 
| 97 | 
            +
              version: 
         | 
| 98 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 99 | 
            +
              requirements: 
         | 
| 100 | 
            +
              - - ">="
         | 
| 101 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 102 | 
            +
                  version: "0"
         | 
| 103 | 
            +
              version: 
         | 
| 104 | 
            +
            requirements: []
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            rubyforge_project: merb
         | 
| 107 | 
            +
            rubygems_version: 1.3.1
         | 
| 108 | 
            +
            signing_key: 
         | 
| 109 | 
            +
            specification_version: 2
         | 
| 110 | 
            +
            summary: Merb plugin that provides composition of controllers.
         | 
| 111 | 
            +
            test_files: []
         | 
| 112 | 
            +
             |