Ruby 모듈의 상수 범위
mixin 모듈에서 일정한 범위에 약간의 문제가 있습니다. 내가 이런 걸 가지고 있다고합시다
module Auth
USER_KEY = "user" unless defined? USER_KEY
def authorize
user_id = session[USER_KEY]
def
end
USER_KEY 상수는 이미 정의되어 있지 않는 한 "user"로 기본 설정되어야합니다. 이제 이것을 몇 군데로 섞을 수도 있지만, 그 중 한 곳에서는 USER_KEY가 달라야하므로 다음과 같은 것이있을 수 있습니다.
class ApplicationController < ActionController::Base
USER_KEY = "my_user"
include Auth
def test_auth
authorize
end
end
USER_KEY가 이미 정의되어 있기 때문에 권한 부여에 사용될 때 "my_user"가 될 것으로 예상하지만 여전히 USER_KEY의 모듈 정의에서 가져온 "user"입니다. 누구나 USER_KEY의 클래스 버전을 사용할 수있는 권한을 얻는 방법을 알고 있습니까?
USER_KEY
당신은 (심지어 조건부)에서 선언 Auth
세계적으로 알려져 있습니다 Auth::USER_KEY
. 모듈을 포함 하는 것은 정규화되지 않은 방식으로 키를 참조 할 수 있지만 모듈 포함에 "혼합"되지 않습니다 .
각 포함 모듈 (예 :)이 ApplicationController
자체 정의 할 수 있도록하려면 다음을 USER_KEY
시도하십시오.
module Auth
DEFAULT_USER_KEY = 'user'
def self.included(base)
unless base.const_defined?(:USER_KEY)
base.const_set :USER_KEY, Auth::DEFAULT_USER_KEY
end
end
def authorize
user_id = session[self.class.const_get(:USER_KEY)]
end
end
class ApplicationController < ActionController::Base
USER_KEY = 'my_user'
include Auth
end
이 모든 문제를 해결하려면 클래스 메서드로 만드는 것이 좋습니다.
module Auth
DEFAULT_USER_KEY = 'user'
def self.included(base)
base.extend Auth::ClassMethods
base.send :include, Auth::InstanceMethods
end
module ClassMethods
def user_key
Auth::DEFAULT_USER_KEY
end
end
module InstanceMethods
def authorize
user_id = session[self.class.user_key]
end
end
end
class ApplicationController < ActionController::Base
def self.user_key
'my_user'
end
end
또는 클래스 수준 접근 자 :
module Auth
DEFAULT_USER_KEY = 'user'
def self.included(base)
base.send :attr_accessor :user_key unless base.respond_to?(:user_key=)
base.user_key ||= Auth::DEFAULT_USER_KEY
end
def authorize
user_id = session[self.class.user_key]
end
end
class ApplicationController < ActionController::Base
include Auth
self.user_key = 'my_user'
end
상수는 Ruby에서 전역 범위가 없습니다. 상수는 모든 범위에서 볼 수 있지만 상수를 찾을 위치를 지정해야합니다. 새 클래스, 모듈 또는 def를 시작할 때 새 범위를 시작하고 다른 범위의 상수를 원하면 찾을 위치를 지정해야합니다.
X = 0
class C
X = 1
module M
X = 2
class D
X = 3
puts X # => 3
puts C::X # => 1
puts C::M::X # => 2
puts M::X # => 2
puts ::X # => 0
end
end
end
여기에 간단한 해결책이 있습니다.
변경 사항 :
- 의 존재 여부를 확인할 필요가 없습니다
USER_KEY
. - 수신기의 모듈 / 클래스에서 상수를 찾아보십시오 (귀하의 경우 컨트롤러가 될 것입니다). 존재한다면 그것을 사용하고, 그렇지 않으면 기본 모듈 / 클래스를 사용하십시오 (기본값은 아래 참조).
.
module Auth
USER_KEY = "user"
def authorize
user_key = self.class.const_defined?(:USER_KEY) ? self.class::USER_KEY : USER_KEY
user_id = session[user_key]
def
end
설명
당신이보고있는 동작은 레일에만 국한된 것이 아니라 루비가 명시 적으로 범위가 지정되지 않은 경우 상수를 찾는 위치 때문입니다 ::
(위의 "기본값"이라고 부름). 상수는 "현재 실행중인 코드의 어휘 범위"를 사용하여 조회됩니다. 이것은 Ruby가 먼저 실행 코드의 모듈 (또는 클래스)에서 상수를 찾은 다음 해당 범위에 정의 된 상수를 찾을 때까지 각 연속 둘러싸는 모듈 (또는 클래스)로 바깥쪽으로 이동 함을 의미합니다.
컨트롤러에서 authorize
. 그러나 authorize
가 실행될 때 현재 실행중인 코드는 Auth
. 그래서 그것이 상수를 찾는 곳입니다. 인증에는 USER_KEY
없지만 포함하는 모듈에 포함 된 경우 포함하는 모듈이 사용됩니다. 예:
module Outer
USER_KEY = 'outer_key'
module Auth
# code here can access USER_KEY without specifying "Outer::"
# ...
end
end
이것의 특별한 경우는 클래스에 속하는 것으로 취급되는 최상위 실행 환경 Object
입니다.
USER_KEY = 'top-level-key'
module Auth
# code here can access the top-level USER_KEY (which is actually Object::USER_KEY)
# ...
end
한 가지 함정은 범위 지정 연산자 ( ::
)를 사용하여 모듈 또는 클래스를 정의하는 것입니다 .
module Outer
USER_KEY = 'outer_key'
end
module Outer::Auth
# methods here won't be able to use USER_KEY,
# because Outer isn't lexically enclosing Auth.
# ...
end
상수는 메서드가 정의 된 것보다 훨씬 늦게 정의 될 수 있습니다. 조회는 USER_KEY에 액세스 할 때만 발생하므로 다음과 같이 작동합니다.
module Auth
# don't define USER_KEY yet
# ...
end
# you can't call authorize here or you'll get an uninitialized constant error
Auth::USER_KEY = 'user'
# now you can call authorize.
프로젝트가 Rails에 있거나 최소한 ActiveSupport
모듈을 사용하는 경우 필요한 논리 설탕을 크게 줄일 수 있습니다.
module Auth
extend ActiveSupport::Concern
included do
# set a global default value
unless self.const_defined?(:USER_KEY)
self.const_set :USER_KEY, 'module_user'
end
end
end
class ApplicationController < ActionController::Base
# set an application default value
USER_KEY = "default_user"
include Auth
end
class SomeController < ApplicationController
# set a value unique to a specific controller
USER_KEY = "specific_user"
end
I'm surprised no one suggested this approach, seeing as how the OP's scenario resided within a Rails app...
There's a far simpler solution to the OP's question than the other answers here reveal:
module Foo
THIS_CONST = 'foo'
def show_const
self.class::THIS_CONST
end
end
class Bar
include Foo
THIS_CONST ='bar'
def test_it
show_const
end
end
class Baz
include Foo
def test_it
show_const
end
end
2.3.1 :004 > r = Bar.new
=> #<Bar:0x000000008be2c8>
2.3.1 :005 > r.test_it
=> "bar"
2.3.1 :006 > z = Baz.new
=> #<Baz:0x000000008658a8>
2.3.1 :007 > z.test_it
=> "foo"
It was @james-a-rosen's answer that gave me the inspiration to try this. I didn't want to go his route because I had several constants that are shared among several classes, each with a different value, and his method looked like a lot of typing.
ReferenceURL : https://stackoverflow.com/questions/2687276/scope-of-constants-in-ruby-modules
'developer tip' 카테고리의 다른 글
Dictionary.keyscollection을 문자열 배열로 변환 (0) | 2021.01.11 |
---|---|
Linux에서 두 SQLite 데이터베이스를 비교하는 방법 (0) | 2021.01.11 |
JavaScript에서 CPU 코어 수를 얻습니까? (0) | 2021.01.11 |
Sublime Text 3에서 기본 코드 조각을 변경하는 방법은 무엇입니까? (0) | 2021.01.10 |
Rails 개발 로그를 어떻게 볼 수 있습니까? (0) | 2021.01.10 |