pup 1.0.0
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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +10 -0
- data/.hound.yml +5 -0
- data/.rspec +2 -0
- data/.rubocop.yml +242 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +174 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/db/data.sqlite +0 -0
- data/lib/pup.rb +12 -0
- data/lib/pup/application.rb +54 -0
- data/lib/pup/controller/base_controller.rb +57 -0
- data/lib/pup/dependencies/method_override.rb +11 -0
- data/lib/pup/dependencies/request_handler.rb +38 -0
- data/lib/pup/model/columns_builder.rb +41 -0
- data/lib/pup/model/model.rb +101 -0
- data/lib/pup/model/orm_methods.rb +56 -0
- data/lib/pup/routing/route.rb +44 -0
- data/lib/pup/routing/route_helpers.rb +31 -0
- data/lib/pup/routing/router.rb +84 -0
- data/lib/pup/utilities/array.rb +9 -0
- data/lib/pup/utilities/object.rb +6 -0
- data/lib/pup/utilities/string.rb +18 -0
- data/lib/pup/version.rb +3 -0
- data/pup.gemspec +50 -0
- metadata +286 -0
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/console
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "bundler/setup"
         | 
| 4 | 
            +
            require "pup"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # You can add fixtures and/or initialization code here to make experimenting
         | 
| 7 | 
            +
            # with your gem easier. You can also use a different console, if you like.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # (If you use this, don't forget to add pry to your Gemfile!)
         | 
| 10 | 
            +
            # require "pry"
         | 
| 11 | 
            +
            # Pry.start
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require "irb"
         | 
| 14 | 
            +
            IRB.start
         | 
    
        data/bin/setup
    ADDED
    
    
    
        data/db/data.sqlite
    ADDED
    
    | Binary file | 
    
        data/lib/pup.rb
    ADDED
    
    | @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            require "pup/version"
         | 
| 2 | 
            +
            require "pup/utilities/string"
         | 
| 3 | 
            +
            require "pup/utilities/object"
         | 
| 4 | 
            +
            require "pup/utilities/array"
         | 
| 5 | 
            +
            require "pup/model/model"
         | 
| 6 | 
            +
            require "pup/routing/router"
         | 
| 7 | 
            +
            require "pup/controller/base_controller"
         | 
| 8 | 
            +
            require "pup/application"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            module Pup
         | 
| 11 | 
            +
              # Your code goes here...
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            require "rack"
         | 
| 2 | 
            +
            require "pup/dependencies/request_handler"
         | 
| 3 | 
            +
            require "pup/dependencies/method_override"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Pup
         | 
| 6 | 
            +
              class Application
         | 
| 7 | 
            +
                attr_reader :request, :verb, :path, :router
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                alias_method :routes, :router
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize
         | 
| 12 | 
            +
                  @router = Routing::Router.new
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def call(env)
         | 
| 16 | 
            +
                  env = MethodOverride.apply_to(env)
         | 
| 17 | 
            +
                  @request = Rack::Request.new(env)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  if router.has_routes?
         | 
| 20 | 
            +
                    respond_to_request
         | 
| 21 | 
            +
                  else
         | 
| 22 | 
            +
                    pup_default_response
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def respond_to_request
         | 
| 27 | 
            +
                  route = router.get_match(request.request_method, request.path_info)
         | 
| 28 | 
            +
                  if route
         | 
| 29 | 
            +
                    handler = RequestHandler.new(request, route)
         | 
| 30 | 
            +
                    handler.response
         | 
| 31 | 
            +
                  else
         | 
| 32 | 
            +
                    page_not_found
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def pup_default_response
         | 
| 37 | 
            +
                  Rack::Response.new(
         | 
| 38 | 
            +
                    "<center><b>Pup ::: </b>MVC Framework for web masters</center>",
         | 
| 39 | 
            +
                    200,
         | 
| 40 | 
            +
                    "Content-Type" => "text/html"
         | 
| 41 | 
            +
                  )
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def page_not_found
         | 
| 45 | 
            +
                  Rack::Response.new(
         | 
| 46 | 
            +
                    "<center><h1>404 Error</h1>Page not found</center>",
         | 
| 47 | 
            +
                    404,
         | 
| 48 | 
            +
                    "Content-Type" => "text/html"
         | 
| 49 | 
            +
                  )
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                private :respond_to_request, :pup_default_response, :page_not_found
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require "active_support/core_ext/hash/indifferent_access"
         | 
| 2 | 
            +
            require "erubis"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Pup
         | 
| 5 | 
            +
              class BaseController
         | 
| 6 | 
            +
                attr_reader :request
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(request)
         | 
| 9 | 
            +
                  @request ||= request
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def get_response
         | 
| 13 | 
            +
                  @response
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def render(view_name, locals = {})
         | 
| 17 | 
            +
                  template = get_template(view_name)
         | 
| 18 | 
            +
                  parameters = build_view_params(locals)
         | 
| 19 | 
            +
                  response_body = Erubis::Eruby.new(template).result(parameters)
         | 
| 20 | 
            +
                  make_response(response_body)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def get_template(view_name)
         | 
| 24 | 
            +
                  filename = File.join(
         | 
| 25 | 
            +
                    APP_ROOT, "app", "views", controller_name, "#{view_name}.erb"
         | 
| 26 | 
            +
                  )
         | 
| 27 | 
            +
                  File.read(filename)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def build_view_params(locals)
         | 
| 31 | 
            +
                  hash = {}
         | 
| 32 | 
            +
                  vars = instance_variables
         | 
| 33 | 
            +
                  vars.each { |name| hash[name] = instance_variable_get(name) }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  hash.merge(locals)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def make_response(body, status = 200, headers = {})
         | 
| 39 | 
            +
                  @response = Rack::Response.new(body, status, headers)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def params
         | 
| 43 | 
            +
                  request.params.with_indifferent_access
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def redirect_to(location)
         | 
| 47 | 
            +
                  make_response([], 302, "Location" => location)
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def controller_name
         | 
| 51 | 
            +
                  self.class.to_s.gsub("Controller", "").to_snakecase
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                private :get_template, :build_view_params, :make_response, :params,
         | 
| 55 | 
            +
                        :redirect_to, :controller_name
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            module Pup
         | 
| 2 | 
            +
              class RequestHandler
         | 
| 3 | 
            +
                attr_reader :request, :route, :response
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(request, route)
         | 
| 6 | 
            +
                  @request = request
         | 
| 7 | 
            +
                  @route = route
         | 
| 8 | 
            +
                  process_request
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def process_request
         | 
| 12 | 
            +
                  params = collage_parameters
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  request.instance_variable_set "@params", params
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  controller_constant = route.controller
         | 
| 17 | 
            +
                  controller_class = controller_constant.new(request)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  @response = controller_response(controller_class, route.action.to_sym)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def collage_parameters
         | 
| 23 | 
            +
                  route_url_params = route.get_url_parameters(request.path_info)
         | 
| 24 | 
            +
                  request.params.merge(route_url_params)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def controller_response(controller, action)
         | 
| 28 | 
            +
                  controller.send(action)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  unless controller.get_response
         | 
| 31 | 
            +
                    controller.render(action)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                  controller.get_response
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                private :process_request, :collage_parameters, :controller_response
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            module Pup
         | 
| 2 | 
            +
              module ColumnsBuilder
         | 
| 3 | 
            +
                private
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def fields_builder(fields)
         | 
| 6 | 
            +
                  columns_definition = ""
         | 
| 7 | 
            +
                  fields.each do |field, constraints|
         | 
| 8 | 
            +
                    columns_definition += field.to_s
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    constraints.each do |constraint_type, value|
         | 
| 11 | 
            +
                      columns_definition += " "
         | 
| 12 | 
            +
                      columns_definition += send(constraint_type, value)
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                    columns_definition += ","
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                  columns_definition[0..-2]
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def type(value)
         | 
| 20 | 
            +
                  value.to_s.upcase
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def primary_key(value)
         | 
| 24 | 
            +
                  return "PRIMARY KEY" if value
         | 
| 25 | 
            +
                  ""
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def nullable(value)
         | 
| 29 | 
            +
                  return "NOT NULL" unless value
         | 
| 30 | 
            +
                  "NULL"
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def default(value)
         | 
| 34 | 
            +
                  "DEFAULT `#{value}`"
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def autoincrement(value)
         | 
| 38 | 
            +
                  "AUTOINCREMENT" if value
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,101 @@ | |
| 1 | 
            +
            require "sqlite3"
         | 
| 2 | 
            +
            require "pup/model/columns_builder"
         | 
| 3 | 
            +
            require "pup/model/orm_methods"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Pup
         | 
| 6 | 
            +
              class Model
         | 
| 7 | 
            +
                extend Pup::ColumnsBuilder
         | 
| 8 | 
            +
                extend Pup::OrmMethods
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                DB ||= SQLite3::Database.new(File.join("db", "data.sqlite"))
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def initialize
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def save
         | 
| 16 | 
            +
                  if id
         | 
| 17 | 
            +
                    query = "UPDATE #{self.class.table_name} "\
         | 
| 18 | 
            +
                            "SET #{update_field_set} "\
         | 
| 19 | 
            +
                            "WHERE id = ?"
         | 
| 20 | 
            +
                    DB.execute(query, table_values, id)
         | 
| 21 | 
            +
                  else
         | 
| 22 | 
            +
                    query = "INSERT INTO #{self.class.table_name} "\
         | 
| 23 | 
            +
                            "(#{table_fields}) "\
         | 
| 24 | 
            +
                            "VALUES(#{values_placeholders})"
         | 
| 25 | 
            +
                    DB.execute(query, table_values)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    self.id = DB.execute("SELECT last_insert_rowid()")
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                  self.class.find(id)
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def update(parameters)
         | 
| 33 | 
            +
                  parameters.each do |key, value|
         | 
| 34 | 
            +
                    send("#{key}=", value)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  save
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def destroy
         | 
| 41 | 
            +
                  DB.execute("DELETE FROM #{self.class.table_name} WHERE id= ?", id)
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def table_fields
         | 
| 45 | 
            +
                  columns_except_id.join(", ")
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def columns_except_id
         | 
| 49 | 
            +
                  self.class.columns_array.without_id.with_value(self)
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def values_placeholders
         | 
| 53 | 
            +
                  count = columns_except_id.count
         | 
| 54 | 
            +
                  (["?"] * count).join(", ")
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def table_values
         | 
| 58 | 
            +
                  values = []
         | 
| 59 | 
            +
                  columns_except_id.each do |field|
         | 
| 60 | 
            +
                    values << send(field)
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                  values
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def update_field_set
         | 
| 66 | 
            +
                  values = []
         | 
| 67 | 
            +
                  columns_except_id.each do |field|
         | 
| 68 | 
            +
                    values << "#{field} = ? "
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                  values.join(", ")
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                class << self
         | 
| 74 | 
            +
                  attr_reader :table_name, :fields
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  def to_table(table_name)
         | 
| 77 | 
            +
                    @table_name = table_name.to_s
         | 
| 78 | 
            +
                    @fields = {}
         | 
| 79 | 
            +
                    property :id, type: :integer, primary_key: true
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  def property(field_name, options = {})
         | 
| 83 | 
            +
                    @fields[field_name] = options
         | 
| 84 | 
            +
                    attr_accessor field_name
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  def create_table
         | 
| 88 | 
            +
                    query = "CREATE TABLE IF NOT EXISTS #{@table_name}"\
         | 
| 89 | 
            +
                            "(#{fields_builder(@fields)})"
         | 
| 90 | 
            +
                    DB.execute(query)
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  def columns_array
         | 
| 94 | 
            +
                    @columns_array ||= fields.keys
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                private :table_fields, :columns_except_id, :values_placeholders,
         | 
| 99 | 
            +
                        :table_values, :update_field_set
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            module Pup
         | 
| 2 | 
            +
              module OrmMethods
         | 
| 3 | 
            +
                # columns_array and table_name are defined in the extending
         | 
| 4 | 
            +
                # class-model/base
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                DB ||= SQLite3::Database.new(File.join("db", "data.sqlite"))
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def create(parameters)
         | 
| 9 | 
            +
                  model = new
         | 
| 10 | 
            +
                  parameters.each do |key, value|
         | 
| 11 | 
            +
                    model.send("#{key}=", value)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  model.save
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def all
         | 
| 18 | 
            +
                  fields = columns_array.join(", ")
         | 
| 19 | 
            +
                  data = DB.execute("SELECT id, #{fields} FROM #{table_name}")
         | 
| 20 | 
            +
                  data.map! do |row|
         | 
| 21 | 
            +
                    row_to_model(row)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  data
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def row_to_model(row)
         | 
| 28 | 
            +
                  model = new
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  columns_array.each_with_index do |field, index|
         | 
| 31 | 
            +
                    model.send("#{field}=", row[index + 1]) if row
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  model
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def find(id)
         | 
| 38 | 
            +
                  fields = columns_array.join(", ")
         | 
| 39 | 
            +
                  row = DB.execute(
         | 
| 40 | 
            +
                    "SELECT id, #{fields} FROM #{table_name} WHERE id = ?",
         | 
| 41 | 
            +
                    id
         | 
| 42 | 
            +
                  ).first
         | 
| 43 | 
            +
                  row_to_model(row) if row
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def destroy(id)
         | 
| 47 | 
            +
                  DB.execute("DELETE FROM #{table_name} WHERE id= ?", id)
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def destroy_all
         | 
| 51 | 
            +
                  DB.execute("DELETE FROM #{table_name}")
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                private :row_to_model
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            module Pup
         | 
| 2 | 
            +
              module Routing
         | 
| 3 | 
            +
                class Route
         | 
| 4 | 
            +
                  attr_reader :controller_name, :action, :path_regex, :url_placeholders
         | 
| 5 | 
            +
                  def initialize(path_regex, to, url_placeholders = {})
         | 
| 6 | 
            +
                    @controller_name, @action = get_controller_and_action(to)
         | 
| 7 | 
            +
                    @path_regex = path_regex
         | 
| 8 | 
            +
                    @url_placeholders = url_placeholders
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def get_controller_and_action(to)
         | 
| 12 | 
            +
                    controller, action = to.split("#")
         | 
| 13 | 
            +
                    controller_name = controller + "_controller"
         | 
| 14 | 
            +
                    [controller_name, action]
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def controller
         | 
| 18 | 
            +
                    Object.const_get(controller_name.to_camelcase)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def get_url_parameters(actual_path)
         | 
| 22 | 
            +
                    parameters = {}
         | 
| 23 | 
            +
                    path = actual_path.split("/")
         | 
| 24 | 
            +
                    url_placeholders.each do |index, key|
         | 
| 25 | 
            +
                      parameters[key] = path[index.to_i]
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                    parameters
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def check_path(path)
         | 
| 31 | 
            +
                    (path_regex =~ path) == 0
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def ==(other)
         | 
| 35 | 
            +
                    controller_name == other.controller_name &&
         | 
| 36 | 
            +
                      action == other.action &&
         | 
| 37 | 
            +
                      path_regex == other.path_regex &&
         | 
| 38 | 
            +
                      url_placeholders == other.url_placeholders
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  private :get_controller_and_action
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         |