0

I am creating a gem that has some model, controller and view components in it. I need to emulate a rails like mvc pattern for it. There are two options that come to my mind and I need to choose one of them. The following code is a simpler extraction of the problem.

Pattern1

project/model.rb

module Application
  module Namespace
    class Model
      def name
        'Mr. Model'
      end
    end
  end
end

project/controller.rb

module Application
  module Namespace
    class Controller
      def action
        Model.new.name
      end
    end
  end
end

project/application.rb

require_relative 'controller'
require_relative 'model'

module Application
  class Runner
    def run
      Namespace::Controller.new.action
    end
  end
end

Pattern2

project/model.rb

class Model
  def name
    'Mr. Model'
  end
end

project/controller.rb

class Controller
  def action
    Model.new.name
  end
end

project/application.rb

module Application
  module Namespace
    module_eval File.read(File.expand_path '../controller.rb', __FILE__)
    module_eval File.read(File.expand_path '../model.rb', __FILE__)
  end

  class Runner
    def run
      Namespace::Controller.new.action
    end
  end
end

irb(main):001:0> require 'project/application' 
=> true
irb(main):002:0> Application::Runner.new.run
=> "Mr. Model"

Both patterns include the models and controllers under a namespace, but with the pattern1 whenever I add new files, I will have to duplicate the ugly modular nesting. The pattern2 creates cleaner models and controllers with some extra magic being done in the application.

I would like some suggestions on these approaches or if there are better solutions to the problem. Questions like why a mvc pattern is needed anyways will be complicated to answer. Lets assume that a mvc pattern is needed and try to answer whats the cleanest way to emulate it.

EDIT:

On further thoughts, Rails uses subclasses. So we have a third pattern now.

Pattern3

project/application_controller.rb

module Application
  module Namespace
    class ApplicationController
    end
  end
end

project/active_model.rb

module Application
  module Namespace
    class ActiveModel
    end
  end
end

project/model.rb

class Model < Application::Namespace::ActiveModel
  def name
    'Mr. Model'
  end
end

project/controller.rb

class Controller < Application::Namespace::ApplicationController
  def action
    Model.new.name
  end
end

project/application.rb

module Application
  require_relative 'active_model'
  require_relative 'application_controller'
  require_relative 'controller'
  require_relative 'model'

  class Runner
    def run
      Controller.new.action
    end
  end
end

Still looking for some brighter ideas.

1
  • Not an answer, just two cents: the explicit module nesting per file can be really helpful and makes the code self–documenting. I really value code that explains itself. Commented Mar 20, 2013 at 6:36

2 Answers 2

2

FWIW, you can rewrite this

module Application
  module Namespace
    class Model
      def name
        'Mr. Model'
      end
    end
  end
end

into this

# do this once
module Application
  module Namespace
  end
end

class Application::Namespace::Model
  def name
    'Mr. Model'
  end
end

Doesn't it remove subjective "ugliness"?

Sign up to request clarification or add additional context in comments.

3 Comments

That does look better. I am however now more inclined towards pattern3.
I didn't realize that pattern3 is placing my models under the global namespace. I am going with your answer. I just need one other clarification. Why do all gems have that nested pattern? Does the community in general find it more clearer?
@Alex: some of that probably stems from how code is physically organized into files/folders, but yeah, logical grouping with modules does more good than harm.
0

It may be better to use Rails engines in this case. It will namespace things properly for you.

https://guides.rubyonrails.org/engines.html

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.