Commit 1e29715e

mo khan <mo@mokhan.ca>
2014-05-17 22:25:00
build small pub/sub system and reorganize services directory as per DDD notion of services.
1 parent 2cc6eed
app/models/creation.rb
@@ -38,12 +38,6 @@ class Creation < ActiveRecord::Base
     favorites.find_or_create_by(user: user)
   end
 
-  def publish_message_with(publisher)
-    if is_safe_for_children? && published?
-      publisher.update("#{name} By #{user.name} on https://www.cakeside.com/creations/#{to_param}!") 
-    end
-  end
-
   class << self
     def search(query)
       sql_search = "%#{query}%"
app/services/application/handlers/publish_cake_to_twitter.rb
@@ -0,0 +1,26 @@
+class PublishCakeToTwitter
+  def initialize(twitter_publisher, configuration = ENV)
+    @twitter = twitter_publisher
+    @configuration = configuration
+  end
+
+  def handles?(event)
+    :new_creation_added == event
+  end
+
+  def handle(message)
+    tweet_about(Creation.find(message[:creation_id]))
+  end
+
+  private
+
+  def tweet_about(cake)
+    @twitter.tweet(tweet_for(cake)) if cake.is_safe_for_children? && cake.published?
+  end
+
+  def tweet_for(cake)
+    "#{cake.name} By #{cake.user.name} on https://www.cakeside.com/creations/#{cake.to_param}!"
+  end
+
+  handle_asynchronously :handle, :run_at => Proc.new { 1.hour.from_now }
+end
app/services/commands/add_to_favorites.rb → app/services/application/add_to_favorites.rb
File renamed without changes
app/services/commands/change_password.rb → app/services/application/change_password.rb
File renamed without changes
app/services/create_cake_command.rb → app/services/application/create_cake_command.rb
@@ -1,8 +1,8 @@
 class CreateCakeCommand
-  def initialize(context, current_user = context.current_user, publisher = TwitterPublisher.new)
+  def initialize(context, current_user = context.current_user, message_bus = Spank::IOC.resolve(:message_bus))
     @context = context
     @current_user = current_user
-    @publisher = publisher
+    @message_bus = message_bus
   end
 
   def run(creation_attributes, category_id, tags)
@@ -11,7 +11,7 @@ class CreateCakeCommand
     @current_user.tag(cake, with: tags, on: :tags)
 
     if cake.save
-      @publisher.publish(cake)
+      @message_bus.publish(:new_creation_added, creation_id: cake.id)
       @context.create_cake_succeeded(cake)
     else
       @context.create_cake_failed(cake)
app/services/queries/find_all_creations_query.rb → app/services/application/find_all_creations_query.rb
File renamed without changes
app/services/queries/find_creation_query.rb → app/services/application/find_creation_query.rb
File renamed without changes
app/services/commands/migrate_primary_image.rb → app/services/application/migrate_primary_image.rb
File renamed without changes
app/services/commands/recreate_photo_versions.rb → app/services/application/recreate_photo_versions.rb
File renamed without changes
app/services/commands/remove_cake_command.rb → app/services/application/remove_cake_command.rb
File renamed without changes
app/services/update_cake_command.rb → app/services/application/update_cake_command.rb
File renamed without changes
app/services/commands/upload_image_worker.rb → app/services/application/upload_image_worker.rb
File renamed without changes
app/services/infrastructure/environment_variables.rb
@@ -0,0 +1,9 @@
+class EnvironmentVariables
+  def initialize(configuration = ENV)
+    @configuration = configuration
+  end
+
+  def [](key)
+    @configuration[key]
+  end
+end
app/services/infrastructure/message_bus.rb
@@ -0,0 +1,17 @@
+class MessageBus
+  def initialize(container)
+    @container = container
+  end
+
+  def publish(event, payload)
+    handlers_for(event).each { |handler| handler.handle(payload) }
+  end
+
+  private
+
+  def handlers_for(event)
+    @container.resolve_all(:message_handler).find_all do |handler|
+      handler.handles?(event)
+    end
+  end
+end
app/services/twitter_publisher.rb → app/services/infrastructure/twitter_publisher.rb
@@ -1,14 +1,12 @@
 class TwitterPublisher
-  def initialize(configuration = ENV)
+  def initialize(configuration)
     @configuration = configuration
   end
 
-  def publish(target)
-    target.publish_message_with(create_client) unless Rails.env.test?
+  def tweet(message)
+    create_client.update(message) unless Rails.env.test?
   end
 
-  handle_asynchronously :publish, :run_at => Proc.new { 1.hour.from_now }
-
   private
 
   def create_client
config/initializers/container.rb
@@ -0,0 +1,7 @@
+container = Spank::Container.new
+container.register(:configuration) { EnvironmentVariables.new }
+container.register(:message_handler) { |builder| builder.build(PublishCakeToTwitter) }
+container.register(:message_bus) { |c| MessageBus.new(c) }.as_singleton
+container.register(:twitter_publisher) { |c| c.build(TwitterPublisher) }.as_singleton
+
+Spank::IOC.bind_to(container)
config/application.rb
@@ -18,11 +18,10 @@ module Cake
     # -- all .rb files in that directory are automatically loaded.
 
     # Custom directories with classes and modules you want to be autoloadable.
-    config.autoload_paths += %W(#{config.root}/app/services)
-    config.autoload_paths += %W(#{config.root}/app/services/commands)
-    config.autoload_paths += %W(#{config.root}/app/services/dto)
-    config.autoload_paths += %W(#{config.root}/app/services/mappers)
-    config.autoload_paths += %W(#{config.root}/app/services/queries)
+    config.autoload_paths += %W(#{config.root}/app/services/application)
+    config.autoload_paths += %W(#{config.root}/app/services/application/handlers)
+    config.autoload_paths += %W(#{config.root}/app/services/domain)
+    config.autoload_paths += %W(#{config.root}/app/services/infrastructure)
 
     # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
     # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
Gemfile
@@ -33,6 +33,7 @@ gem 'unf'
 gem 'exception_notification'
 gem 'gibbon'
 gem 'twitter'
+gem 'spank'
 
 group :development do
   gem 'capistrano'
Gemfile.lock
@@ -262,6 +262,7 @@ GEM
       multi_json
       simplecov-html (~> 0.8.0)
     simplecov-html (0.8.0)
+    spank (0.0.1393558686)
     sprockets (2.11.0)
       hike (~> 1.2)
       multi_json (~> 1.0)
@@ -359,6 +360,7 @@ DEPENDENCIES
   sdoc
   selenium-webdriver
   simplecov
+  spank
   sqlite3
   teaspoon
   twitter