Permalink
Browse files

lots of fixes and changes

  • Loading branch information...
1 parent 881e631 commit 58f72d0472d4cc12ea04c0b0a713dd3f72378e9e @kristianmandrup committed Aug 1, 2012
View
@@ -96,4 +96,87 @@ module PostController
end
end
end
-```
+```
+
+## Restfull Commands
+
+If you inherit from the `Imperator::Command::Restfull` class, you gain access to the
+REST convenience methods: `update`, `delete` and `create_new` which creates action methods with some default appropriate REST logic for the particular action.
+See the code for more info on how to use this for your own needs.
+
+```ruby
+class UpdatePostCommand < Imperator::Command::Restfull
+ attribute :some_object_id
+ attribute :some_value
+
+ validates_presence_of :some_object_id
+
+ update do
+ puts "updated OK"
+ end
+end
+```
+
+## Mongoid integration
+
+Imperator also comes with a little Mongodi adaptor class, which provides the `attributes_for` method in order to easily redefine Mongoid model fields as Command attributes. Similar adaptors could be created for other ORMs such as Active Record etc.
+
+```ruby
+class UpdatePostCommand < Imperator::Mongoid::RestCommand
+
+ attributes_for Post, except: [:status, :rating]
+
+ validates :name, presence: true
+
+ update do
+ puts "#{object} was updated"
+ end
+
+ on_error do
+ puts "The Post could not be updated: #{object}"
+ end
+end
+```
+
+## Class Factory
+
+The `Imperator::Command::ClassFactory` can be used to easily create Command wrappers for your model classes.
+
+```ruby
+Imperator::Command::ClassFactory.create :publish, Post do
+ action do
+ find_object.publish!
+ end
+end
+```
+
+It is especially handy for creating Rest Command wrappers.
+
+```ruby
+
+Imperator::Command::ClassFactory.use do |factory|
+ factory.default_rest_class = Imperator::Mongoid::RestCommand
+ factory.create_rest :all, Post do
+ on_error do
+ puts "Oops! There was an error!"
+ end
+ end
+
+ factory.create_rest :update, Article do
+ attributes_for Article
+
+ on_error do
+ puts "Oops! There was an error!"
+ end
+ end
+
+ # Same using :auto_attributes option
+ factory.create_rest :update, Article, auto_attributes: true do
+ on_error do
+ puts "Oops! There was an error!"
+ end
+ end
+end
+```
+
+
View
@@ -1,8 +1,12 @@
require "imperator/version"
-require 'imperator/invalid_command_error'
+require 'imperator/errors'
require 'imperator/command'
+require 'imperator/command/restfull'
+require 'imperator/command/class_factory'
require 'imperator/focused' if defined?(FocusedController)
+require 'imperator/mongoid' if defined?(Mongoid)
+
module Imperator
# Your code goes here...
View
@@ -1,6 +1,7 @@
require 'uuid'
require 'active_model'
require 'virtus'
+
class Imperator::Command
include ActiveModel::Validations
extend ActiveModel::Callbacks
@@ -25,6 +26,10 @@ def self.action(&block)
alias_method :params, :attributes
+ def self.attributes_for clazz, options = {}
+ raise NotImplementedError
+ end
+
def to_s
str = "Command: #{id}"
str << " - #{object}" if object
@@ -0,0 +1,76 @@
+class Imperator::Command
+ # http://johnragan.wordpress.com/2010/02/18/ruby-metaprogramming-dynamically-defining-classes-and-methods/
+ class ClassFactory
+ class << self
+ def use &block
+ yield self
+ end
+
+ # Usage:
+ # Imperator::Command::ClassFactory.create :update, Post, parent: Imperator::Mongoid::Command do
+ # ..
+ # end
+ def create action, model, options = {}, &block
+ parent = options[:parent] || Imperator::Command
+ clazz = Class.new parent do
+ attributes_for(model, :except => options[:except]) if options[:auto_attributes]
+ yield
+ end
+ Kernel.const_set "#{action}#{model}Command", clazz
+ end
+
+ # Usage:
+ # Imperator::Command::ClassFactory.create_rest :all, Post, parent: Imperator::Mongoid::Command do
+ # ..
+ # end
+ def create_rest action, model, options = {}, &block
+ parent = options[:parent] || default_rest_class
+ create_rest_all(model, options = {}, &block) and return if action.to_sym == :all
+ if rest_actions.include? action.to_sym
+ send "create_rest_#{action}", model, options, &block
+ else
+ raise ArgumentError, "Not a supported REST action. Must be one of #{rest_actions}, was #{action}"
+ end
+ end
+
+ attr_writer :default_rest_class
+
+ def default_rest_class
+ @default_rest_class ||= Imperator::Command::Restfull
+ end
+
+ protected
+
+ def rest_actions
+ [:new, :update, :delete]
+ end
+
+ def create_rest_new model, options = {}, &block
+ create :update, model, options do
+ update
+ yield
+ end
+ end
+
+ def create_rest_update model, options = {}, &block
+ create :update, model, options do
+ update
+ yield
+ end
+ end
+
+ def create_rest_delete model, options = {}, &block
+ create :delete, model, options do
+ delete
+ yield
+ end
+ end
+
+ def create_rest_all model, options = {}, &block
+ rest_actions.each do |action|
+ send "create_rest_#{action}", model, options, &block
+ end
+ end
+ end
+ end
+end
@@ -0,0 +1,50 @@
+class Imperator::Command
+ module Rest
+ attribute :object_class, Object
+
+ def self.create_new &block
+ action do
+ object_class.create attribute_set if object_class
+ yield
+ end
+ end
+
+ def self.update &block
+ action do
+ find_object.update_attributes attribute_set if find_object
+ yield
+ rescue e: Imperator::ResourceNotFoundError
+ on_error e
+ end
+ end
+
+ def self.delete &block
+ action do
+ find_object.delete
+ yield
+ end
+ end
+
+ def self.on_error &block
+ define_method(:on_error, &block)
+ end
+
+ def self.for_class clazz
+ object_class = clazz
+ end
+
+ def on_error exception
+ raise Imperator::InvalidCommandError, "The Command #{self} caused an error: #{exception}"
+ end
+
+ def find_object
+ object ||= object_class.find(self.id)
+ rescue
+ find_object_error
+ end
+
+ def find_object_error
+ raise Imperator::ResourceNotFoundError, "The resource #{self.id} could not be found"
+ end
+ end
+end
@@ -0,0 +1,7 @@
+require 'imperator/command/rest'
+
+class Imperator::Command
+ class RestFull < Imperator::Command
+ include Imperator::Command::Rest
+ end
+end
View
@@ -0,0 +1,4 @@
+class Imperator::InvalidCommandError < ArgumentError; end
+
+class Imperator::ResourceNotFoundError < StandardError; end
+
View
@@ -1,2 +1,7 @@
+module Imperator
+ module Focused
+ end
+end
+
require 'imperator/focused/command_action'
require 'imperator/focused/rest_actions'
Oops, something went wrong.

0 comments on commit 58f72d0

Please sign in to comment.