manison wrote:Ten jednoduchý příklad se Salamander.MsgBox mi právě funguje. Domníval jsem se, že by to mohlo být dané "scopem" proměnné. Na globální úrovni to funguje, ale v té třídě LargeFiles asi nikoliv. Jazyk Ruby neznám, ale pochopil jsem, že viditelnost proměnných se řeší pomocí prefixů $, @ apod. Automation přidává objekt Salamander do skriptovacího stroje pomocí metody
AddNamedItem. To jsem dopátral až do metody
add_named_item a tam jsem skončil. Dokážete vysvětlit, o co tam jde?
Aha. Tak to je dobře. Máte pravdu, že viditelnost je daná určitými prefixy - tato funkcionalita je určená pro objektové použití ruby a funkcionlitu zvanou mixin - třída do sebe nabalí funkcionalitu definovanou moduly - tudíž ji nemusí definovat v třídě.
Abych byl konkrétní:
$ - definuje globální proměnou (globalní viditelnost)
@ - instační proměná (definované pouze v instanci třídy)
@@ - třídní proměná (existuje ve třídě)
Vytvořil jsem jednoduchý skript, který demostruje přístupnost promněných všechno kromě @@
Code: Select all
module AddToClass
def honking
if @honk == 1
p 'HOOONK'
else
p 'silence'
end
end
def set_honk
@honk = 100
end
end
module ShowAccessVariable
module ReallyShow
attr_accessor :last_test
#ahoj = 1 # does not work in TestScope
TEST = 10
#@kde_jsem = 20 # does not work either
$mega_test = 400
@var_test = 'uzasne'
def self.print
p @var_test
end
def self.show_last_test
@last_test = 'bazzinga'
end
end
end
class TestScope
attr_accessor :cink, :honk
include AddToClass
include ShowAccessVariable
def initialize(value)
@honk = value
@cink = 1
end
@cink = 100 # does nothing => value is still init
def show_variable
p "Showing test: #{ReallyShow::TEST}" # CONSTANT -> due to the include ShowAccessVariable you don't have to do ShowAccessVariable::ReallyShow::TEST
#p ReallyShow.ahoj # this produces an error as undefined method 'ahoj' -> ahoj is defined as local variable
#p "Showing test: #{ReallyShow.kde_jsem}" # Does not show because of the fact that this is an instance variable that belongs to ShowAccessVariable::ReallyShow
p $mega_test # global variable
p "Printing the @var_test: #{ReallyShow.print}"
p "Printing the @last_value: #{ReallyShow.show_last_test}"
end
end
testing = TestScope.new(1)
p testing.cink
testing.honking
testing.set_honk
p testing.honk
p testing.cink # still prints 1
testing.show_variable
Výstup:
Code: Select all
1
"HOOONK"
100
1
"Showing test: 10"
400
"uzasne"
"Printing the @value: uzasne"
"Printing the @value: bazzinga"
Code: Select all
def add_named_item(name, obj, global)
@named_items[name] = NamedItem.new(obj, global)
if name[0].between?('A', 'Z')
GlobalProxy.const_set(name, obj)
else
define_singleton_method(name.to_sym) { obj }
end
if global
@global = obj
end
# ASR 1.0 compatibility
instance_eval("@#{name} = #{name}")
GlobalProxy.const_set(name.capitalize, obj)
end
K tomu kódu methody
add_named_item
metoda add_named_item příjímá 3 proměnné name, obj, global.
`name` je podle všeho název NamedItem (coz je Struct.new(:obj, :global)) # : znamená symbol
`obj` instance objektu asr (GlobalProxy < AsrProxy) ? (usuzuji z metody create_event_proc a create_event_handler)
`global` asi oveřuje scope dané probměnné či objektu obj (jestli je lokální či globální)
`@named_items` => je inicializován jako prázdná instance třídy Hash.
První řádek dělá to, že zapíše od @named_items záznam (name je klíč, a nová instance NamedItem je hodnotou) {name => instance_NamedItem}.
První if testuje jestli první písmeno je veliké což v Ruby znamená, že daná NamedItem je konstata, v ostatních případech vytvoří jedinečnou metodu
(viz:
http://apidock.com/ruby/Object/define_singleton_method)
Druhý if asi vytváří globální objekt (s globální působností?) => pouze moje domněka na základě kódu. A do instanční proměnné @global uloží obj
Ten zbytek je tam z legacy důvodů a dělá vlastně podobné operace ale jednodušeji.
# ASR 1.0 compatibility
instance_eval("@#{name} = #{name}") # ukládá hodnotu lokální proměnné name do instační proměnné @name
GlobalProxy.const_set(name.capitalize, obj) # Vytvaří pro objekt/třídu GlobalProxy konstatní jmeno tím, že vezme jméno a udělá z něho
# velká písmena a pomcí metody const_set vytvoří konstantu pro daný obj
Je to takhle lepší?