Čovječe, gdje mi je konstanta?

Pita se: Nikola Šantić

Developeri vole fileove

require

# a.rb
puts "Hello from A"
# b.rb
require "a.rb"
# => "Hello from A"

Kernel#require

def require(file)
  eval File.read(file)
end
$LOAD_PATH = []

def require(file)
  full_path = $LOAD_PATH.first do |path|
    File.exists?(File.join(path, file))
  end

  eval File.read(full_path)
end
$LOADED_FEATURES = []

def require(file)
  if $LOADED_FEATURES.include?(file)
    return true
  end

  eval File.read(file)
  $LOADED_FEATURES << file
end

require

u praksi

 

class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end
require 'application_controller'
require 'post'
 
class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end

:/

autoloading

+ reloading

Ruby autoload

# lib/special_library.rb
class SpecialLibrary
  puts "Hello!"
end
# main.rb
autoload :special_library, "lib/special_library"
#...
SpecialLibrary.new # => Hello!

Constant lookup

module A
  module B
    class C < D
      p WALDO
      # 1. Module.nesting => [A::B::C, A::B, A]
      # 2. Module.nesting.first.ancestors 
      #      => [A::B::C, D, Object, Kernel, BasicObject]
      # 3. A ako ne...
    end
  end
end
module A
  module B
    class C < D
      p WALDO
      # 1. Module.nesting => [A::B::C, A::B, A]
      # 2. Module.nesting.first.ancestors 
      #      => [A::B::C, D, Object, Kernel, BasicObject]
    end
  end
end
module A
  module B
    class C < D
      p WALDO
      # 1. Module.nesting => [A::B::C, A::B, A]
    end
  end
end
module A
  module B
    class C < D
      p WALDO
    end
  end
end

const_missing

manje poznati rođak method_missinga

module Foo
  def self.const_missing(name)
    puts "In #{self} looking for #{name}..."
    super
  end
end

Što sad?

MyModule::SomeClass # => my_module/some_class.rb
config.autoload_paths # => 
    # ./apps/*
    # ./apps/{controllers,models}/*

config.autoload_paths << Rails.root.join("lib")

Name mapping:

Pretraživanje:

U međuvremenu...

C = "At the top level"

module A
  C = "In A"
end

module A
  module B
    puts Module.nesting # => [A::B, A]
    puts C              # => "In A"
  end
end

module A::B
  puts Module.nesting # => [A::B]
  puts C              # => "At the top level"
end
 # /lib/b.rb
 module B
 end

 # /lib/a.rb
 module A
   B # => B
 end
 # /lib/b.rb
 module B
 end

 # /lib/a.rb
 module A
 end

 p A::B # => B
# qux.rb
Qux = "I'm at the root!"

# foo.rb
module Foo
end

# foo/qux.rb
module Foo
  Qux = "I'm in Foo!"
end

# foo/bar.rb
class Foo::Bar
  def self.print_qux
    puts Qux
  end
end

Foo::Bar.print_qux
# qux.rb
Qux = "I'm at the root!"

# foo.rb
module Foo
end

# foo/qux.rb
module Foo
  Qux = "I'm in Foo!"
end

# foo/bar.rb
class Foo::Bar
  def self.print_qux
    puts Qux
  end
end

Foo::Bar.print_qux # => "I'm in Foo!"
# qux.rb
Qux = "I'm at the root!"

# foo.rb
module Foo
end

# foo/qux.rb
module Foo
  Qux = "I'm in Foo!"
end

# foo/bar.rb
class Foo::Bar
  def self.print_qux
    puts Qux
  end
end

Foo::Bar.print_qux # => "I'm in Foo!"
Foo::Bar.print_qux
# qux.rb
Qux = "I'm at the root!"

# foo.rb
module Foo
end

# foo/qux.rb
module Foo
  Qux = "I'm in Foo!"
end

# foo/bar.rb
class Foo::Bar
  def self.print_qux
    puts Qux
  end
end

Foo::Bar.print_qux # => "I'm in Foo!"
Foo::Bar.print_qux # NameError: uninitialized constant Foo::Bar::Qux

Pouka: koristite ::C

A Gemovi?

# config/application.rb
Bundler.require(*Rails.groups)

Zaključak

rails-autoloading

By Nikola Šantić