module A; end                # Pusty modu.
module B; include A; end;    # Modu B docza modu A.
class C; include B; end;     # Klasa C docza modu B.
C < B               # => true  C docza B.
B < A               # => true  B docza A.
C < A                # => true
Fixnum < Integer     # => true  wszystkie obiekty klasy Fixnum nale do klasy Integer.
Integer < Comparable # => true  liczby cakowite mona porwnywa.
Integer < Fixnum     # => false  nie wszystkie obiekty klasy Integer nale do klasy Fixnum.
String < Numeric     # => nil  acuchy nie s liczbami.
A.ancestors          # => [A]
B.ancestors          # => [B, A]
C.ancestors          # => [C, B, A, Object, Kernel]
String.ancestors     # => [String, Enumerable, Comparable, Object, Kernel]
                     # Uwaga: w Ruby 1.9 klasa String nie jest ju przeliczalna.
C.include?(B)        # => true
C.include?(A)        # => true
B.include?(A)        # => true
A.include?(A)        # => false
A.include?(B)        # => false
A.included_modules   # => []
B.included_modules   # => [A]
C.included_modules   # => [B, A, Kernel]

module Greeter; def hi; "witaj"; end; end # Mao przydatny modu.
s = "obiekt klasy String"
s.extend(Greeter)       # Dodanie hi jako metody singletonowej do obiektu s.
s.hi                    # => "witaj".
String.extend(Greeter)  # Dodanie hi jako metody klasowej klasy String.
String.hi               # => "witaj".

module M
  class C
    Module.nesting   # => [M::C, M]
  end
end

M = Module.new      # Definicja nowego moduu o nazwie M.
C = Class.new       # Definicja nowej klasy o nazwie C.
D = Class.new(C) {  # Definicja podklasy klasy C,
  include M         # ktra docza modu M.
}
D.to_s              # => D  klasa zdobywa nazw staej w czarodziejski sposb.

x = 1
eval "x + 1"  # => 2

class Object     # Otwarcie klasy Object, aby doda now metod.
  def bindings   # Nazwa tej metody ma form liczby mnogiej.
    binding      # To jest predefiniowana metoda moduu Kernel.
  end
end
class Test       # Prosta klasa ze zmienn egzemplarza.
  def initialize(x); @x = x; end
end
t = Test.new(10)       # Utworzenie obiektu klasy Test.
eval("@x", t.bindings) # => 10  zajrzelimy do rodka obiektu t.

o.instance_eval("@x")  # Zwraca warto zmiennej egzemplarza @x obiektu o.
# Definiuje metod egzemplarza o nazwie len klasy String zwracajc dugo acucha.
String.class_eval("def len; size; end")
# Oto inny sposb na zrobienie tego.
String.class_eval("alias len size")
# Definicja metody klasowej String.empty za pomoc metody instance_eval.
# Zwr uwag, e cudzysowy w cudzysowach robi si nieco niebezpieczne...
String.instance_eval("def empty; ''; end")

o.instance_eval { @x }
String.class_eval {
  def len
    size
  end
}
String.class_eval { alias len size }
String.instance_eval { def empty; ""; end }

global_variables   # => ["$DEBUG", "$SAFE", ...]
x = 1              # Definicja zmiennej lokalnej.
local_variables    # => ["x"]
# Definicja prostej klasy.
class Point
  def initialize(x,y); @x,@y = x,y; end # Definicja zmiennych egzemplarza.
  @@classvar = 1                        # Definicja zmiennej klasowej.
  ORIGIN = Point.new(0,0)               # Definicja staej.
end
Point::ORIGIN.instance_variables # => ["@y", "@x"]
Point.class_variables            # => ["@@classvar"]
Point.constants                  # => ["ORIGIN"]

x = 1
varname = "x"
eval(varname)           # => 1
eval("varname = '$g'")  # Ustawia varname na "$g".
eval("#{varname} = x")  # Ustawia $g na 1.
eval(varname)           # => 1

o = Object.new
o.instance_variable_set(:@x, 0)   # Zauwa wymagany prefiks @.
o.instance_variable_get(:@x)      # => 0
o.instance_variable_defined?(:@x) # => true
Object.class_variable_set(:@@x, 1)   # Prywatna w Ruby 1.8.
Object.class_variable_get(:@@x)      # Prywatna w Ruby 1.8.
Object.class_variable_defined?(:@@x) # => true; Ruby 1.9 i pniejsze wersje.
Math.const_set(:EPI, Math::E*Math::PI)
Math.const_get(:EPI)             # => 8.53973422267357
Math.const_defined? :EPI         # => true

String.class_eval { class_variable_set(:@@x, 1) }  # Ustawienie zmiennej @@x w klasie String.
String.class_eval { class_variable_get(:@@x) }     # => 1

o.instance_eval { remove_instance_variable :@x }
String.class_eval { remove_class_variable(:@@x) }
Math.send :remove_const, :EPI  # Wywoanie metody prywatnej za pomoc metody send.

def Symbol.const_missing(name)
  name # Zwrcenie nazwy staej jako symbolu.
end
Symbol::Test   # => :Test  niezdefiniowana staa zostaje efektywnie skonwertowana na symbol.

o = "acuch"
o.methods                # => [ nazwy wszystkich metod publicznych ].
o.public_methods         # => to samo.
o.public_methods(false)  # Wyczenie metod odziedziczonych.
o.protected_methods      # => []  nie ma adnych.
o.private_methods        # => Tablica wszystkich metod prywatnych.
o.private_methods(false) # Wyczenie odziedziczonych metod prywatnych.
def o.single; 1; end     # Definicja metody singletonowej.
o.singleton_methods      # => ["single"] (lub [:single] w 1.9).

String.instance_methods == "s".public_methods                # => true
String.instance_methods(false) == "s".public_methods(false)  # => true
String.public_instance_methods == String.instance_methods    # => true
String.protected_instance_methods       # => []
String.private_instance_methods(false)  # => ["initialize_copy",
                                        #     "initialize"]

Math.singleton_methods  # => ["acos", "log10", "atan2", ... ]

String.public_method_defined? :reverse     # => true
String.protected_method_defined? :reverse  # => false
String.private_method_defined? :initialize # => true
String.method_defined? :upcase!            # => true

"s".method(:reverse)             # => Obiekt klasy Method.
String.instance_method(:reverse) # => Obiekt klasy UnboundMethod.

"witaj".send :upcase        # => "WITAJ": wywoanie metody egzemplarza.
Math.send(:sin, Math::PI/2) # => 1.0: wywoanie metody klasowej.

"witaj".send :puts, "wiecie"         # Drukuje "wiecie".

"witaj".public_send :puts, "wiecie"  # Powoduje wyjtek NoMethodError.

# Dodanie metody egzemplarza o nazwie m do klasy c z ciaem b.
def add_method(c, m, &b)
  c.class_eval {
    define_method(m, &b)
  }
end
add_method(String, :greet) { "Witaj, " + self }
"wiecie".greet   # => "Witaj, wiecie".

def add_class_method(c, m, &b)
  eigenclass = class << c; self; end
  eigenclass.class_eval {
    define_method(m, &b)
  }
end
add_class_method(String, :greet) {|name| "Witaj, " + name }
String.greet("wiecie")  # => "Witaj, wiecie".

String.define_singleton_method(:greet) {|name| "Witaj, " + name }

alias plus +         # Sowo plus jest synonimem operatora +.

# Utworzenie aliasu dla metody m w klasie (lub module) c.
def backup(c, m, prefix="original")
  n = :"#{prefix}_#{m}"    # Wyznaczenie aliasu.
  c.class_eval {           # Poniewa metoda alias_method jest prywatna.
    alias_method n, m      # n jest aliasem m.
  }
end
backup(String, :reverse)
"test".original_reverse # => "tset"

class Hash
  # Pozwala na sprawdzanie i ustawianie wartoci kluczy, jakby byy atrybutami.
  # Symulujemy gettery i settery atrybutw dla kadego klucza.
  def method_missing(key, *args)
    text = key.to_s
    if text[-1,1] == "="               # Jeli klucz koczy si znakiem =, ustawia warto.
      self[text.chop.to_sym] = args[0] # Usunicie znaku = z klucza.
    else                               # W przeciwnym przypadku...
      self[key]                        # ... zwracana jest warto klucza.
    end
  end
end
h = {}         # Utworzenie pustego obiektu.
h.one = 1      # To samo, co h[:one] = 1.
puts h.one     # Drukuje 1. To samo, co puts h[:one].

String.class_eval { private :reverse }
"witaj".reverse  # NoMethodError: private method 'reverse'.

# Czyni wszystkie metody klasy Math prywatnymi.
# Teraz, aby wywoa metod moduu Math, musimy go domiesza.
Math.private_class_method *Math.singleton_methods

def Object.inherited(c)
  puts "class #{c} < #{self}"
end

module Final             # Nie mona tworzy podklas klasy doczajcej modu Final.
  def self.included(c)   # W przypadku doczenia tego moduu do klasy c,
    c.instance_eval do   # zdefiniuj metod klasow klasy c
      def inherited(sub) # wykrywajc podklasy i
        raise Exception, # anulujc operacje ich tworzenia za pomoc wyjtku.
              "Prba utworzenia podklasy #{sub} klasy finalnej #{self}"
      end
    end
  end
end

def String.method_added(name)
  puts "Nowa metoda egzemplarza #{name} zostaa dodana do klasy String."
end

def String.singleton_method_added(name)
  puts "Nowa metoda klasowa #{name} zostaa dodana do klasy String."
end

# Doczenie tego moduu do klasy powoduje, e do jej egzemplarzy nie mona
# dodawa metod singletonowych. Wszystkie dodane metody singletonowe s
# usuwane.
module Strict
  def singleton_method_added(name)
    STDERR.puts "Ostrzeenie: metoda singletonowa #{name} zostaa dodana do obiektu Strict."
    eigenclass = class << self; self; end
    eigenclass.class_eval { remove_method name }
  end
end

STDERR.puts "#{__FILE__}:#{__LINE__): nieprawidowe dane"

raise "Bd w #{__method__} at #{__FILE__}:#{__LINE__}"

SCRIPT_LINES__ = {__FILE__ => File.readlines(__FILE__)}

SCRIPT_LINES__[__FILE__][__LINE__-1]

# Drukuje komunikat po kadej zmianie wartoci zmiennej $SAFE.
trace_var(:$SAFE) {|v|
  puts "Warto zmiennej $SAFE zostaa ustawiona na #{v} w #{caller[1]}"
}

# Drukuje list wszystkich znanych klas.
ObjectSpace.each_object(Class) {|c| puts c }

require 'afterevery'
1.upto(5) {|i| after i { puts i } } # Powoli drukuje cyfry od 1 do 5.
sleep(5)                            # Czeka 5 sekund.
every 1, 6 do |count|               # Powoli drukuje liczby od 6 do 10.
  puts count
  break if count == 10
  count + 1                         # Kolejna warto zmiennej count.
end
sleep(6)                            # Daje czas wtkowi na zakoczenie dziaania.

#
# Definicja metod after i every z moduu Kernel, aby opniay wykonywanie blokw kodu.
# Przykady:
#
#   after 1 { puts "koniec" }
#   every 60 { redraw_clock }
#
# Obie te metody zwracaj obiekty klasy Thread. Aby anulowa wykonywanie tego kodu,
# naley wywoa metod kill na rzecz tych obiektw.
#
# Pamitaj, e jest to bardzo prosta implementacja. Bardziej niezawodna wersja,
# dla wszystkich zada uywaaby jednego globalnego wtku mierzcego czas oraz
# umoliwiaaby sprawdzanie wartoci opnionego bloku i poczekanie
# na zakoczenie wszystkich zada.
#
# Wykonuje blok kodu po odczekaniu wyznaczonej liczby sekund.
def after(seconds, &block)
  Thread.new do     # Nowy wtek...
    sleep(seconds)  # Pierwsze zanicie.
    block.call      # Wywoanie bloku.
  end               # Zwrcenie natychmiast obiektu klasy Thread.
end
# Wielokrotnie usypia, a nastpnie wykonuje blok kodu.
# Przekazuje do bloku warto przy pierwszym wywoaniu.
# Do kolejnych wywoa przekazuje warto poprzedniego wywoania.
def every(seconds, value=nil, &block)
  Thread.new do                 # Nowy wtek...
    loop do                     # Powtarzanie w nieskoczono (lub do instrukcji break w bloku)
      sleep(seconds)            # Zanicie.
      value = block.call(value) # Wywoanie bloku.
    end                         # Nastpne powtrzenie..
  end                           # Metoda every zwraca obiekt klasy Thread.
end

# Pozyskanie muteksu zwizanego z obiektem o i wykonanie
# bloku pod ochron tego muteksu.
# Dziaa podobnie do sowa kluczowego Javy synchronized.
def synchronized(o)
  o.mutex.synchronize { yield }
end
# Metoda Object.mutex nie istnieje, a wic trzeba j zdefiniowa.
# Metoda ta zwraca unikatowy muteks dla kadego obiektu i dla poszczeglnych
# obiektw zwraca zawsze ten sam muteks.
# Muteksy s tworzone leniwie, co wymaga synchronizacji ze wzgldu na
# bezpieczestwo wtkw.
class Object
  # Metoda ta zwraca muteks dla tego obiektu, tworzc go w razie potrzeby.
  # Sztuka polega na tym, aby dwa rne wtki nie wywoay
  # jej jendoczenie, tworzc dwa rne muteksy.
  def mutex
    # Jeli ten obiekt posiada ju muteks, zostanie on zwrcony.
    return @__mutex if @__mutex

    # W przeciwnym przypadku konieczne jest utworzenie muteksu dla tego obiektu.
    # Aby byo bezpiecznie, konieczna jest synchronizacja naszego obiektu klasy.
    synchronized(self.class) {
      # Ponowne sprawdzenie: od czasu wejcia do tego synchronizowanego bloku
      # jaki inny wtek mg ju utworzy ten muteks.
      @__mutex = @__mutex || Mutex.new
    }
    # Wartoci zwrotn jest @__mutex.
  end
end
# Zdefiniowana powyej metoda Object.mutex musi zablokowa klas, jeli
# obiekt nie ma jeszcze muteksu. Jeli klasa nie posiada jeszcze wasnego muteksu,
# obiekt tej klasy zostanie zablokowany. Aby zapobiec nieskoczonej rekurencji,
# musisz upewni si, e obiekt ten ma muteks.
Class.instance_eval { @__mutex = Mutex.new }

# Niniejszy modu dostarcza staych definiujcych acuchy UTF-8 dla
# wszystkich punktw kodowych Unicode. Definiuje je leniwie za pomoc metody const_missing.
# Przykady:
#   copyright = Unicode::U00A9
#   euro = Unicode::U20AC
#   infinity = Unicode::U221E
module Unicode
  # Niniejsza metoda pozwala na leniwe definiowanie staych punktw kodowych Unicode.
  def self.const_missing(name)  # Niezdefiniowana staa przekazana jako symbol.
    # Sprawdzenie, czy nazwa staej ma poprawny format 
    # musi by wielka litera U z liczb szesnastkow z przedziau 0000 - 10FFFF.
    if name.to_s =~ /^U([0-9a-fA-F]{4,5}|10[0-9a-fA-F]{4})$/
      # $1 to dopasowana liczba szesnastkowa. Zostaje ona przekonwertowana na liczb cakowit.
      codepoint = $1.to_i(16)
      # Konwersja liczby na acuch UTF-8 za pomoc metody Array.pack.
      utf8 = [codepoint].pack("U")
      # Sprawienie, e nie mona modyfikowa tego acucha UTF-8.
      utf8.freeze
      # Definicja prawdziwej staej, aby przyspieszy kolejne wyszukiwania, i zwrcenie
      # tym razem tekstu UTF-8.
      const_set(name, utf8)
    else
      # Zgoszenie wyjtku dla staych w nieprawidowym formacie.
      raise NameError, "Niezainicjowana staa: Unicode::#{name}"
    end
  end
end

a = [1,2,3].trace("a")
a.reverse
puts a[2]
puts a.fetch(3)

Wywoanie: a.reverse() at trace1.rb:66
Zwracanie: [3, 2, 1] from a.reverse to trace1.rb:66
Wywoanie: a.fetch(3) at trace1.rb:67
Zgoszenie: IndexError:index 3 out of array z a.fetch

# Metoda trace dowolnego obiektu tworzy nowy obiekt, ktry zachowuje si
# dokadnie tak samo jak orygina, ale ledzi wszystkie wywoania metod
# na rzecz tego obiektu. W przypadku ledzenia wicej ni jednego obiektu,
# naley poda nazw, ktra ma zosta uyta w danych wyjciowych. Domylnie
# komunikaty bd wysyane do strumienia STDERR, ale mona wyznaczy dowolny strumie
# (lub dowolny obiekt przyjmujcy acuchy jako argumenty do <<).
class Object
  def trace(name="", stream=STDERR)
    # Zwraca ledzcy i delegujcy obiekt klasy TracedObject.
    TracedObject.new(self, name, stream)
  end
end
# Niniejsza klasa ledzi wywoania metod za pomoc metody method_missing i
# deleguje je do jakiego innego obiektu. Usuwa wikszo wasnych
# metod egzemplarza, aby nie wchodziy w konflikty z metod method_missing.
# Zauwa, e ledzone bd tylko metody wywoywane poprzez obiekt klasy TracedObject.
# Jeli obiekt delegowany wywouje metod na swoj rzecz, ledzenia te nie
# s ledzone.
class TracedObject
  # Wszystkie mao wane publiczne metody egzemplarza zostaj oddefiniowane.
  # Zauwa uycie metod Module.instance_methods i Module.undef_method.
  instance_methods.each do |m|
    m = m.to_sym  # Ruby 1.8 zwraca acuchy zamiast symboli.
    next if m == :object_id || m == :__id__ || m == :__send__
    undef_method m
  end
  # Inicjalizacja egzemplarza klasy TracedObject.
  def initialize(o, name, stream)
    @o = o            # Obiekt, do ktrego delegujemy.
    @n = name         # Nazwa obiektu, ktra ma pojawia si w komunikatach.
    @trace = stream   # Miejsce, do ktrego maj by wysyane komunikaty.
  end
  # To jest kluczowa metoda klasy TracedObject. Jest wywoywana dla
  # kadego wywoania metody na rzecz obiektu klasy TracedObject.
  def method_missing(*args, &block)
    m = args.shift         # Pierwszy argument jest nazw metody.
    begin
      # ledzenie wywoa tej metody.
      arglist = args.map {|a| a.inspect}.join(', ')
      @trace << "Wywoywanie: #{@n}.#{m}(#{arglist}) w #{caller[0]}\n"
      # Wywoanie metody na rzecz delegowanego obiektu i odebranie wartoci zwrotnej.
      r = @o.send m, *args, &block
      # ledzenie normalnego zwrotu metody.
      @trace << "Zwracanie: #{r.inspect} z #{@n}.#{m} do #{caller[0]}\n"
      # Zwrcenie wartoci zwrconej przez obiekt delegowany.
      r
    rescue Exception => e
      # ledzenie nienormalnego zwrotu metody.
      @trace << "Zgoszenie: #{e.class}:#{e} z #{@n}.#{m}\n"
      # Ponowne zgoszenie wyjtku zgoszonego przez obiekt delegowany.
      raise
    end
  end
  # Zwrcenie obiektu, do ktrego delegujesz.
  def __delegate
    @o
  end
end

def synchronized(o)
  o.mutex.synchronize { yield }
end

def synchronized(o)
  if block_given?
    o.mutex.synchronize { yield }
  else
    SynchronizedObject.new(o)
  end
end
# Delegacyjna klasa osonowa zapewniajca bezpieczestwo wtkom za pomoc metody method_missing.
# Zamiast rozszerzy klas Object i delegowa metody, rozszerzasz klas
# BasicObject, ktra jest zdefiniowana w Ruby 1.9. Klasa BasicObject nie
# dziedziczy po klasie Object ani module Kernel, a wic jej obiekty nie mog
# wywoywa adnych metod najwyszego poziomu  po prostu ich tam nie ma.
class SynchronizedObject < BasicObject
  def initialize(o); @delegate = o;  end
  def __delegate; @delegate; end
  def method_missing(*args, &block)
    @delegate.mutex.synchronize {
      @delegate.send *args, &block
    }
  end
end

class Module
  private     # Ponisze metody s prywatne.
  # Ta metoda dziaa jak metoda attr_reader, ale ma krtsz nazw.
  def readonly(*syms)
    return if syms.size == 0  # Jeli nie ma argumentw, nie robi nic.
    code = ""                 # Na pocztku jest pusty acuch.
    # Generuje acuch kodu Ruby definiujcy metody odczytujce atrybuty.
    # Zauwa interpolacj symbolu do acucha kodu.
    syms.each do |s|                     # Dla kadego symbolu
      code << "def #{s}; @#{s}; end\n"   # definiowana jest metoda.
    end
    # Tworzenie metod egzemplarza z wygenerowanego kodu za pomoc metody class_eval.
    class_eval code
  end
  # Ta metoda dziaa jak metoda attr_accessor, ale ma krtsz nazw.
  def readwrite(*syms)
    return if syms.size == 0
    code = ""
    syms.each do |s|
      code << "def #{s}; @#{s} end\n"
      code << "def #{s}=(value); @#{s} = value; end\n"
    end
    class_eval code
  end
end

class Point
  attributes :x => 0, :y => 0
end

class Point
  attributes x:0, y:0
end

class Module
  # Niniejsza metoda definiuje metody odczytu i zapisu atrybutw dla wyznaczonych
  # atrybutw, ale przyjmuje jako argument tablic asocjacyjn rzutujc nazwy atrybutw
  # na ich wartoci domylne. Wygenerowane w ten sposb metody odczytu atrybutw zwracaj
  # swoje wartoci domylne, jeli zmienna egzemplarza nie jest jeszcze zdefiniowana.
  def attributes(hash)
    hash.each_pair do |symbol, default|   # Dla kadej pary atrybut/warto domylna.
      getter = symbol                     # Nazwa metody sprawdzajcej.
      setter = :"#{symbol}="              # Nazwa metody ustawiajcej.
      variable = :"@#{symbol}"            # Nazwa zmiennej egzemplarza.
      define_method getter do             # Definicja metody sprawdzajcej.
        if instance_variable_defined? variable
          instance_variable_get variable  # Zwraca zmienn, jeli jest zdefiniowana.
        else
          default                         # W przeciwnym przypadku zwraca warto domyln.
        end
      end
      define_method setter do |value|     # Definicja metody ustawiajcej.
        instance_variable_set variable,   # Ustawienie zmiennej egzemplarza
                              value       # na warto argumentu.
      end
    end
  end
  # Metoda ta dziaa jak metoda attributes, ale definiuje metody klasowe,
  # wywoujc metod attributes na rzecz klasy eigenclass zamiast self.
  # Zdefiniowane metody uywaj zmiennych egzemplarza klasy
  # zamiast zwykych zmiennych klasowych.
  def class_attrs(hash)
    eigenclass = class << self; self; end
    eigenclass.class_eval { attributes(hash) }
  end
  # Obie metody s prywatne.
  private :attributes, :class_attrs
end

require 'classtrace'

ruby -rclasstrace my_program.rb  --traceout /tmp/trace

# Niniejszy modu ma za zadanie przechowywa informacje o stanie globalnym, dziki czemu
# nie ma potrzeby modyfikowa globalnej przestrzeni nazw wicej ni jest to konieczne.
module ClassTrace
  # Niniejsza tablica przechowuje list zaadowanych plikw i zdefiniowanych klas.
  # Kady element jest podtablic zawierajc zdefiniowan klas lub
  # zaadowany plik oraz ramk stosu, na ktrym klas t zdefiniowano lub zaadowano plik.
  T = []  # Tablica przechowujca zaadowane pliki.
  # Teraz zostanie zdefiniowana staa OUT okrelajca, gdzie maj zosta wysane dane ze ledzenia.
  # Domylnie jest to strumie STDERR, ale mona to zmieni za pomoc argumentw wiersza polece.
  if x = ARGV.index("--traceout")    # Jeli argument istnieje,
    OUT = File.open(ARGV[x+1], "w")  # zostaje otwarty wyznaczony plik,
    ARGV[x,2] = nil                  # a argumenty zostaj usunite.
  else
    OUT = STDERR                     # W przeciwnym przypadku stosowana jest warto domylna.
  end
end
# Tworzenie acucha aliasw  krok 1.: definicja aliasw dla oryginalnych metod.
alias original_require require
alias original_load load
# Tworzenie acucha aliasw  krok 2.: definicja nowych wersji tych metod.
def require(file)
  ClassTrace::T << [file,caller[0]]     # Zapamituje, co zostao gdzie zaadowane.
  original_require(file)                # Wywoanie oryginalnej metody.
end
def load(*args)
  ClassTrace::T << [args[0],caller[0]]  # Zapamitanie, co zostao gdzie zaadowane.
  original_load(*args)                  # Wywoanie oryginalnej metody.
end
# Niniejsza metoda zwrotna jest wywoywana w odpowiedzi na definicj kadej klasy.
def Object.inherited(c)
  ClassTrace::T << [c,caller[0]]        # Zapamitanie, co zostao gdzie zdefiniowane.
end
# Metoda Kernel.at_exit rejestruje blok, ktry ma by wykonywany przed zamkniciem programu.
# Za jej pomoc program raportuje zebrane informacje o plikach i klasach.
at_exit {
  o = ClassTrace::OUT
  o.puts "="*60
  o.puts "Zaadowane pliki i zdefiniowane klasy:"
  o.puts "="*60
  ClassTrace::T.each do |what,where|
    if what.is_a? Class  # Raport o zdefiniowanej klasie (z hierarchi).
      o.puts "Zdefiniowano: #{what.ancestors.join('<-')} w #{where}"
    else                 # Raport o zaadowanym pliku.
      o.puts "Zaadowano: #{what} w #{where}"
    end
  end
}

# Definicja metody Module.synchronize_method, ktra tworzy acuchy aliasw metod egzemplarza,
# dziki czemu s one synchronizowane na egzemplarzu przed wykonaniem.
class Module
  # Metoda pomocnicza dla tworzenia acucha aliasw.
  # Majc podan nazw metody (jako acuch lub symbol) i prefiks, tworzy
  # unikatowy alias dla tej metody i zwraca nazw tego aliasu jako symbol.
  # Wszystkie znaki interpunkcyjne w oryginalnej nazwie metody
  # s konwertowane na liczby, dziki czemu mona tworzy aliasy operatorw.
  def create_alias(original, prefix="alias")
    # Przykleja prefiks do oryginalnej nazwy i konwertuje znaki interpunkcyjne.
    aka = "#{prefix}_#{original}"
    aka.gsub!(/([\=\|\&\+\-\*\/\^\!\?\~\%\<\>\[\]])/) {
      num = $1[0]                       # Znak Ruby 1.8 -> porzdkowy.
      num = num.ord if num.is_a? String # Znak Ruby 1.9 -> porzdkowy.
      '_' + num.to_s
    }

    # Dodawanie znakw podkrelenia, a powstanie nazwa, ktra nie jest jeszcze uywana.
    aka += "_" while method_defined? aka or private_method_defined? aka
    aka = aka.to_sym            # Konwersja nazwy aliasu na symbol.
    alias_method aka, original  # Rzeczywiste utworzenie aliasu.
    aka                         # Zwrcenie nazwy aliasu.
  end
  # Dodanie metody do acucha aliasw, aby umoliwi synchronizacj.
  def synchronize_method(m)
    # Najpierw trzeba utworzy alias dla niesynchronizowanej wersji metody.
    aka = create_alias(m, "unsync")
    # Teraz naley przedefiniowa orygina, aby wywoywa alias w synchronizowanym bloku.
    # Chcesz, aby zdefiniowana metoda przyjmowaa bloki, a wic
    # nie moesz uy metody define_method, konieczne jest wykonanie acucha za pomoc
    # metody class_eval. Wszystko pomidzy znakami %Q{ i pasujcym znakiem }
    # jest acuchem w podwjnych cudzysowach, nie blokiem.
    class_eval %Q{
      def #{m}(*args, &block)
        synchronized(self) { #{aka}(*args, &block) }
      end
    }
  end
end
# Niniejszej globalnej synchronizowanej metody mona teraz uywa na trzy rne sposoby.
def synchronized(*args)
  # Przypadek 1.: z jednym argumentem i blokiem, synchronizacja na obiekcie
  # i wykonanie bloku.
  if args.size == 1 && block_given?
    args[0].mutex.synchronize { yield }
  # Przypadek 2.: z jednym argumentem niebdcym symbolem i bez bloku.
  # Zwraca obiekt klasy SynchronizedObject.
  elsif args.size == 1 and not args[0].is_a? Symbol and not block_given?
    SynchronizedObject.new(args[0])
  # Przypadek 3.: w przypadku wywoania na rzecz moduu bez bloku wyznaczone metody czone s w acuch
  # w celu umoliwienia synchronizacji. Lub, jeli nie ma adnych argumentw,
  # do acucha zostaje dodana kolejna zdefiniowana metoda.
  elsif self.is_a? Module and not block_given?
    if (args.size > 0) # Synchronizacja wyznaczonych metod.
      args.each {|m| self.synchronize_method(m) }
    else
      # Jeli nie zostan okrelone adne metody, synchronizacji podlega kolejna zdefiniowana metoda.
      eigenclass = class<<self; self; end
      eigenclass.class_eval do # Uycie klasy eigenclass do zdefiniowania metod klasowych.
        # Definicja metody method_added powiadamiajcej o zdefiniowaniu kolejnej metody.
        define_method :method_added do |name|
          # Najpierw trzeba usun t metod zwrotn.
          eigenclass.class_eval { remove_method :method_added }
          # Nastpnie synchronizujesz metod, ktra wanie zostaa dodana.
          self.synchronize_method name
        end
      end
    end
  # Przypadek 4.: kade inne wywoanie jest bdem.
  else
    raise ArgumentError, "Nieprawidowe argumenty metody synchronize()"
  end
end

# Definicja metod egzemplarza trace! i untrace! dla wszystkich obiektw.
# Metoda trace! tworzy acuch wyznaczonych metod, definiujc metody singletonowe,
# ktre dodaj funkcjonalno ledzenia, a nastpnie wywoujc orygina za pomoc metody super.
# Metoda untrace! usuwa te metody singletonowe, aby pozby si funkcjonalnoci ledzenia.
class Object
  # ledzi wyznaczone metody, wysyajc dane do strumienia STDERR.
  def trace!(*methods)
    @_traced = @_traced || []    # Zapamituje zbir ledzonych metod.
    # Jeli nie zostay wyznaczone adne metody, zostan wzite pod uwag wszystkie metody publiczne
    # zdefiniowane bezporednio (nie odziedziczone) w klasie tego obiektu.
    methods = public_methods(false) if methods.size == 0
    methods.map! {|m| m.to_sym } # Konwertuje wszystkie acuchy na symbole.
    methods -= @_traced          # Usuwa metody, ktre s ju ledzone.
    return if methods.empty?     # Koczy dziaanie wczeniej, jeli nie ma nic do zrobienia.
    @_traced |= methods          # Dodaje metody do zbioru metod ledzonych.
    # ledzi fakt rozpoczcia ledzenia tych metod.
    STDERR << "ledzenie #{methods.join(', ')} w #{object_id}\n"
    # Metody singletonowe s zdefiniowane w klasie eigenclass.
    eigenclass = class << self; self; end
    methods.each do |m|         # Dla kadej metody m.
      # Definicja ledzonej wersji singletonowej metody m.
      # Wysya informacje ledzenia i wywouje za pomoc metody super
      # metod egzemplarza, ktr ledzi.
      # Chcesz, aby definiowane metody mogy przyjmowa bloki, a wic
      # nie moesz uy metody define_method, tylko musisz w zamian wykona acuch.
      # Zauwa, e wszystko, co znajduje si pomidzy znakami %Q{ i pasujcym znakiem } jest
      # acuchem w podwjnych cudzysowach, nie blokiem. Zauwa take, e s
      # dwa poziomy interpolacji acuchw. #{} jest interpolowany, gdy
      # definiowana jest metoda singletonowa. acuch \#{} jest interpolowany, gdy
      # metoda ta jest wywoywana.
      eigenclass.class_eval %Q{
        def #{m}(*args, &block)
          begin
            STDERR << "Wchodzenie: #{m}(\#{args.join(', ')})\n"
            result = super
            STDERR << "Wychodzenie: #{m} z wartoci \#{result}\n"
            result
          rescue
            STDERR << "Anulowanie: #{m}: \#{$!.class}: \#{$!.message}"
            raise
          end
        end
      }
    end
  end
  # Wycza ledzenie wyznaczonych metod lub wszystkich ledzonych metod.
  def untrace!(*methods)
    if methods.size == 0    # Jeli nie zostaa podana adna metoda,
      methods = @_traced    # wszystkie aktualnie ledzone metody przestan by ledzone.
      STDERR << "Wyczanie ledzenia wszystkich metod obiektu #{object_id}\n"
    else                    # W przeciwnym przypadku wycza ledzenie.
      methods.map! {|m| m.to_sym }  # Konwertuje acuchy na symbole.
      methods &= @_traced   # wszystkich wyznaczonych metod, ktre s ledzone.
      STDERR << "Wyczanie ledzenia #{methods.join(', ')} w #{object_id}\n"
    end
    @_traced -= methods     # Usunicie tych metod ze zbioru metod ledzonych.
    # Usuwa ledzone metody singletonowe z klasy eigenclass.
    # Zauwa, e wykonujesz tu za pomoc metody class_eval blok kodu, nie acuch.
    (class << self; self; end).class_eval do
      methods.each do |m|
        remove_method m     # Metoda undef_method nie dziaaaby prawidowo.
      end
    end
    # Jeli adne wicej metody nie s ledzone, usuwasz zmienn egzemplarza.
    if @_traced.empty?
      remove_instance_variable :@_traced
    end
  end
end

pagetitle = "Strona testowa metody  XML.generate"
XML.generate(STDOUT) do
  html do
    head do
      title { pagetitle }
      comment "To jest test."
    end
    body do
      h1(:style => "font-family:sans-serif") { pagetitle }
      ul :type=>"square" do
        li { Time.now }
        li { RUBY_VERSION }
      end
    end
  end
end

<html><head>
<title>Strona testowa metody XML.generate</title>
<!-- To jest test -->
</head><body>
<h1 style='font-family:sans-serif'>Strona testowa metody XML.generate</h1>
<ul type='square'>
<li>2007-08-19 16:19:58 -0700</li>
<li>1.9.0</li>
</ul></body></html>

class XML
  # Utwrz egzemplarz tej klasy, okrelajc strumie lub obiekt do
  # przechowywania danych wyjciowych. Moe to by dowolny obiekt odpowiadajcy na <<(String).
  def initialize(out)
    @out = out  # Zapamituje, gdzie maj zosta wysane dane wyjciowe.
  end
  # Wysya wyznaczony obiekt jako CDATA, zwraca warto nil.
  def content(text)
    @out << text.to_s
    nil
  end
  # Wysya wyznaczony obiekt jako komentarz, zwraca warto nil.
  def comment(text)
    @out << "<!-- #{text} -->"
    nil
  end
  # Wysya znacznik o okrelonej nazwie i z okrelonymi atrybutami.
  # Jeli jest blok, zostanie wywoany, aby wysa lub zwrci tre.
  # Zwraca warto nil.
  def tag(tagname, attributes={})
    # Wysanie nazwy znacznika.
    @out << "<#{tagname}"
    # Wysanie atrybutw.
    attributes.each {|attr,value| @out << " #{attr}='#{value}'" }

    if block_given?
      # Ten blok zawiera tre.
      @out << '>'             # Zakoczenie znacznika otwierajcego.
      content = yield         # Wywoanie bloku, aby wysa lub zwrci tre.
      if content              # Jeli zostaa zwrcona jaka tre,
        @out << content.to_s  # zostanie wysana jako acuch.
      end
      @out << "</#{tagname}>" # Zamknicie znacznika.
    else
      # W przeciwnym przypadku jest to znacznik pusty, a wic zostaje tylko zamknity.
      @out << '/>'
    end
    nil # Znaczniki wysyaj si same, a wic nie zwracaj adnej treci.
  end
  # Poniszy kod odpowiada za zamian tej klasy w jzyk DSL.
  # Po pierwsze: kada nieznana metoda jest traktowana jako nazwa znacznika.
  alias method_missing tag
  # Po drugie: uruchamia blok w nowym egzemplarzu klasy.
  def self.generate(out, &block)
    XML.new(out).instance_eval(&block)
  end
end

class HTMLForm < XMLGrammar
  element :form, :action => REQ,
                 :method => "GET",
                 :enctype => "application/x-www-form-urlencoded",
                 :name => OPT
  element :input, :type => "text", :name => OPT, :value => OPT,
                  :maxlength => OPT, :size => OPT, :src => OPT,
                  :checked => BOOL, :disabled => BOOL, :readonly => BOOL
  element :textarea, :rows => REQ, :cols => REQ, :name => OPT,
                     :disabled => BOOL, :readonly => BOOL
  element :button, :name => OPT, :value => OPT,
                   :type => "submit", :disabled => OPT
end

HTMLForm.generate(STDOUT) do
  comment "Prosty formularz HTML."
  form :name => "registration",
       :action => "http://www.example.com/register.cgi" do
    content "Name:"
    input :name => "name"
    content "Address:"
    textarea :name => "address", :rows=>6, :cols=>40 do
      "Podaj adres e-mail."
    end
    button { "Submit" }
  end
end

class XMLGrammar
  # Utwrz egzemplarz tej klasy, okrelajc strumie lub obiekt do
  # przechowywania danych. Obiekt musi odpowiada na <<(String).
  def initialize(out)
    @out = out  # Gdzie maj by wysyane dane.
  end
  # Wywouje blok w egzemplarzu, ktry wysya dane do wyznaczonego strumienia.
  def self.generate(out, &block)
    new(out).instance_eval(&block)
  end
  # Definiuje dozwolony element (czyli znacznik) w gramatyce.
  # Niniejsza metoda jest jzykiem DSL specyfikujcym gramatyk
  # oraz definiuje metody skadajce si na jzyk DSL generujcy XML.
  def self.element(tagname, attributes={})
    @allowed_attributes ||= {}
    @allowed_attributes[tagname] = attributes
    class_eval %Q{
      def #{tagname}(attributes={}, &block)
        tag(:#{tagname},attributes,&block)
      end
    }
  end
  # Te stae s uywane podczas definiowania wartoci atrybutw.
  OPT = :opt     # Dla atrybutw opcjonalnych.
  REQ = :req     # Dla atrybutw wymaganych.
  BOOL = :bool   # Dla atrybutw, ktrych wartoci jest ich wasna nazwa.
  def self.allowed_attributes
    @allowed_attributes
  end
  # Wysya wyznaczony obiekt jako CDATA, zwraca warto nil.
  def content(text)
    @out << text.to_s
    nil
  end
  # Wysya wyznaczony obiekt jako komentarz, zwraca warto nil.
  def comment(text)
    @out << "<!-- #{text} -->"
    nil
  end
  # Wysya znacznik o wyznaczonej nazwie i z okrelonym atrybutem.
  # Jeli istnieje jaki blok, zostaje wywoany, aby zwrci lub wysa tre.
  # Return nil.
  def tag(tagname, attributes={})
    # Wysya nazw znacznika.
    @out << "<#{tagname}"
    # Sprawdza dozwolone atrybuty tego znacznika.
    allowed = self.class.allowed_attributes[tagname]
    # Najpierw naley si upewni, e kady z tych atrybutw jest dozwolony.
    # Zakadajc, e wszystkie s dozwolone, wysyane s wszystkie wyznaczone.
    attributes.each_pair do |key,value|
      raise "nieznany atrybut: #{key}" unless allowed.include?(key)
      @out << " #{key}='#{value}'"
    end
    # Przeglda dozwolone atrybuty, aby sprawdzi, czy nie zostay
    # pominite adne wymagane atrybuty oraz czy s atrybuty z wartociami
    # domylnymi, ktre mona wysa na wyjcie.
    allowed.each_pair do |key,value|
      # Jeli ten atrybut zosta ju wysany, nic si nie dzieje.
      next if attributes.has_key? key
      if (value == REQ)
        raise "brak wymaganego atrybutu '#{key}' w znaczniku <#{tagname}>"
      elsif value.is_a? String
        @out << " #{key}='#{value}'"
      end
    end
    if block_given?
      # Ten blok zawiera tre.
      @out << '>'             # Zakoczenie znacznika otwierajcego.
      content = yield         # Wywoanie bloku, aby wysa lub zwrci tre.
      if content              # Jeli zostanie zwrcona jaka tre,
        @out << content.to_s  # bdzie wysana na wyjcie jako acuch.
      end
      @out << "</#{tagname}>" # Zamknicie znacznika.
    else
      # W przeciwnym przypadku jest to znacznik pusty, a wic naley tylko go zamkn.
      @out << '/>'
    end
    nil # Znaczniki wysyaj same siebie, a wic nie zwracaj adnej treci.
  end
end

