I am fairly satisfied with my solution here but I would definitely appreciate any constructive criticism of my style and design. The basic idea is to use the strategy pattern to simplify assembling a custom procedural generator. I'm using modules rather than classes for improved simplicity of 'mixing' everything together. Here's the root of the 'strategy' class tree, AbstractStrategy:      #      #    the contract here is that the child strategy should implement an apply      #    function which takes a target problem instance and hash options.      #      module AbstractStrategy        def apply!(problem, opts={})          log.debug --- AbstractStrategy.apply! problem=#{problem}, opts=#{opts}          apply(problem, opts)          end      endOne level down, we have another 'parent' pattern which implements a particular strategy 'action' or 'style'. In this case it's an AbstractGenerationStrategy which implements apply according to the contract above.      #      # the contract here is that the child strategy needs to implement generate_[component]!({})      #      module AbstractGenerationStrategy extend AbstractStrategy        include AbstractStrategy        def extend!(base)          log.debug(--- extending #{base})          self.extend(base)        end        #        # => use like -- generate :rooms, ConstructNestedRoomsStrategy, ...opts...        #        def generate(component, strategy, opts={})          log.debug --- AbstractGenerationStrategy.generate[component=#{component}, strategy=#{strategy}]          extend!(strategy)          apply!(component,opts)        end        def apply(component_to_generate, opts)          log.debug --- AbstractGenerationStrategy.apply component=#{component_to_generate}, opts=#{opts})          self.send(generate_#{component_to_generate}!, opts)        end      endTo see this in action, one strategy module which implements the above contract is AbstractRoomGenerationStrategy:      #      # contract -- expects children to implement generate_room(opts)      #            module AbstractRoomGenerationStrategy extend AbstractGenerationStrategy        include AbstractGenerationStrategy        include LoggingHelpers        DEFAULT_ROOM_COUNT = 3        def generate_rooms!(opts={})          room_count = opts[:count] || DEFAULT_ROOM_COUNT          log.debug generating #{opts[:count]} rooms          room_count.times { generate_room!(opts) }        end      endFinally, a 'concrete' example of an AbstractRoomGenerationStrategy is ConstructSingleHugeRoomStrategy. Note at this point we are expecting to be 'mixed' into (technically, extended from) certain kinds of classes, and so we are expecting certain member variables (like @width and @height) to exist:      module ConstructSingleHugeRoomStrategy extend RoomGenerationStrategy        include RoomGenerationStrategy        def generate_room!(opts={})          @rooms ||= []          log.debug 'generating room'          if @rooms.empty?            place_first_room(opts)          else            # do nothing          end        end        #        #  place a huge room in the center of the space        #        def place_first_room(opts)          log.debug placing first huge room                  default_opts = {             :width => @width/2, :height => @height/2,            :position => [@width/4, @height/4]          }          opts ||= default_opts                  room = Room.new(opts)          log.debug new room created: #{room}          @rooms << room        end      endIn the context of an appropriate class the operation can be invoked likegenerate :rooms, ConstructSingleHugeRoomStrategy, optsHere's a snippet from a test scenario exercising the above strategy:log.info '--- building new space with defaults (no opts)'@@space = Space.new log.debug 'calling space.generate_rooms! with ConstructSingleHugeRoomStrategy'@@space.generate :rooms, ConstructSingleHugeRoomStrategylog.debug 'asserting room count == 1'@@space.rooms.count.should == 1At the moment I can't provide a direct link to more as the repository is in a private bitbucket, though I am happy to try to provide more context if necessary.I'd like feedback on class design and pattern usage (and of course coding style and correctness if you see real problems here.) Note the main goal of using the 'strategies' here was really just to enable me to mix and match algorithms in reusable and relatively straightforward way.
Is this an appropriate class design for the strategy pattern in Ruby?
ruby;design patterns
Stop trying to write Ruby like Java. You've got a whole mess of modules to do something fairly simple.Most (not all) of the Gang of Four patterns are workarounds for lack of flexibility in languages like C++ and Java, and are less necessary in a language like Ruby that has classes that are first-class objects and always extensible.I'd like to know a bit more about your use case, but it seems to me that you can probably remove a layer or two of indirection.