Code-Kommentare

Ruby hat zwei Arten von Kommentaren: Inline- und Blockkommentare.

Inline-Kommentare beginnen mit dem Zeichen # und reichen bis zum Ende der Zeile.

# On a separate line
class Foo # or at the end of the line
  # can be indented
  def bar
  end
end

Blockkommentare beginnen mit =begin und enden mit =end. Beide sollten in einer separaten Zeile stehen.

=begin
This is
commented out
=end

class Foo
end

=begin some_tag
this works, too
=end

=begin und =end dürfen nicht eingerückt werden, dies ist ein Syntaxfehler.

class Foo
  =begin
  Will not work
  =end
end

Magic Comments

Während Kommentare von Ruby normalerweise ignoriert werden, enthalten spezielle "Magic Comments" Direktiven, die beeinflussen, wie der Code interpretiert wird.

Top-Level Magic Comments müssen im ersten Kommentarbereich einer Datei erscheinen.

HINWEIS: Magic Comments beeinflussen nur die Datei, in der sie erscheinen; andere Dateien sind davon nicht betroffen.

# frozen_string_literal: true

var = 'hello'
var.frozen? # => true

Alternative Syntax

Magic Comments können aus einer einzelnen Direktive bestehen (wie im obigen Beispiel). Alternativ können mehrere Direktiven in derselben Zeile erscheinen, wenn sie durch ";" getrennt und von "-*-" umschlossen sind (siehe Emacs' Datei-Variablen).

# emacs-compatible; -*- coding: big5; mode: ruby; frozen_string_literal: true -*-

p 'hello'.frozen? # => true
p 'hello'.encoding # => #<Encoding:Big5>

encoding Direktive

Gibt an, welche String-Kodierung für String-Literale, Regex-Literale und __ENCODING__ verwendet werden soll.

# encoding: big5

''.encoding # => #<Encoding:Big5>

Die Standardkodierung ist UTF-8.

Top-Level Magic Comments müssen in der ersten Zeile stehen oder in der zweiten Zeile, wenn die erste Zeile wie eine #! shebang Zeile aussieht.

Das Wort "coding" kann anstelle von "encoding" verwendet werden.

frozen_string_literal Direktive

Gibt an, dass String-Literale einmal zur Parse-Zeit allokiert und eingefroren werden sollen.

# frozen_string_literal: true

3.times do
  p 'hello'.object_id # => prints same number
end
p 'world'.frozen? # => true

Der Standardwert ist false. Dies kann mit --enable=frozen-string-literal geändert werden. Ohne die Direktive oder mit # frozen_string_literal: false würde das obige Beispiel 3 verschiedene Zahlen und "false" ausgeben.

Ab Ruby 3.0 werden dynamische String-Literale nicht eingefroren oder wiederverwendet.

# frozen_string_literal: true

p "Addition: #{2 + 2}".frozen? # => false

Es muss im ersten Kommentarbereich einer Datei erscheinen.

warn_indent Direktive

Diese Direktive kann die Erkennung von fehlerhafter Einrückung für nachfolgende Anweisungen einschalten.

def foo
  end # => no warning

# warn_indent: true
def bar
  end # => warning: mismatched indentations at 'end' with 'def' at 6

Eine andere Möglichkeit, diese Warnungen anzuzeigen, ist die Ausführung von Ruby mit Warnungen (ruby -w). Die Verwendung einer Direktive, um dies auf false zu setzen, verhindert, dass diese Warnungen angezeigt werden.

shareable_constant_value Direktive

Hinweis: Diese Direktive ist in Ruby 3.0 experimentell und kann sich in zukünftigen Versionen ändern.

Diese spezielle Direktive hilft dabei, Konstanten zu erstellen, die nur unveränderliche Objekte oder Ractor-fähige Konstanten enthalten.

Die Direktive kann eine spezielle Behandlung für Werte angeben, die Konstanten zugewiesen werden.

Modus none (Standard)

In diesem Modus keine spezielle Behandlung (wie in Ruby 2.x): kein automatisches Einfrieren und keine Prüfungen.

Es war schon immer eine gute Idee, Konstanten tief einzufrieren; Ractor macht dies zu einer noch besseren Idee, da nur der Haupt-Ractor auf nicht teilbare Konstanten zugreifen kann.

# shareable_constant_value: none
A = {foo: []}
A.frozen? # => false
Ractor.new { puts A } # => can not access non-shareable objects by non-main Ractor.

Modus literal

Im Modus "literal" werden Konstanten, die Literalen zugewiesen werden, tief eingefroren.

# shareable_constant_value: literal
X = [{foo: []}] # => same as [{foo: [].freeze}.freeze].freeze

Andere Werte müssen teilbar sein.

# shareable_constant_value: literal
X = Object.new # => cannot assign unshareable object to X

Beachten Sie, dass nur Literale, die direkt Konstanten zugewiesen werden, oder solche, die rekursiv in solchen Literalen enthalten sind, eingefroren werden.

# shareable_constant_value: literal
var = [{foo: []}]
var.frozen? # => false (assignment was made to local variable)
X = var # => cannot assign unshareable object to X

X = Set[1, 2, {foo: []}].freeze # => cannot assign unshareable object to X
                                # (`Set[...]` is not a literal and
                                # `{foo: []}` is an argument to `Set.[]`)

Die Methode Module#const_set ist nicht betroffen.

Modus experimental_everything

In diesem Modus werden alle Konstanten zugewiesenen Werte teilbar gemacht.

# shareable_constant_value: experimental_everything
FOO = Set[1, 2, {foo: []}]
# same as FOO = Ractor.make_shareable(...)
# OR same as `FOO = Set[1, 2, {foo: [].freeze}.freeze].freeze`

var = [{foo: []}]
var.frozen? # => false (assignment was made to local variable)
X = var # => calls `Ractor.make_shareable(var)`
var.frozen? # => true

Dieser Modus ist "experimentell", da er fehleranfällig sein kann, zum Beispiel durch tiefes Einfrieren der Konstanten einer externen Ressource, was zu Fehlern führen könnte.

# shareable_constant_value: experimental_everything
FOO = SomeGem::Something::FOO
# => deep freezes the gem's constant!

Dies wird vor Ruby 3.1 überarbeitet, um entweder "everything" zuzulassen oder diesen Modus stattdessen zu entfernen.

Die Methode Module#const_set ist nicht betroffen.

Modus experimental_copy

In diesem Modus werden alle Konstanten zugewiesenen Werte tief kopiert und teilbar gemacht. Es ist ein sichererer Modus als experimental_everything.

# shareable_constant_value: experimental_copy
var = [{foo: []}]
var.frozen? # => false (assignment was made to local variable)
X = var # => calls `Ractor.make_shareable(var, copy: true)`
var.frozen? # => false
Ractor.shareable?(X) #=> true
var.object_id == X.object_id #=> false

Dieser Modus ist "experimentell" und wurde nicht gründlich diskutiert. Dies wird vor Ruby 3.1 überarbeitet, um entweder "copy" zuzulassen oder diesen Modus stattdessen zu entfernen.

Die Methode Module#const_set ist nicht betroffen.

Scope

Diese Direktive kann mehrmals in derselben Datei verwendet werden.

# shareable_constant_value: none
A = {foo: []}
A.frozen? # => false
Ractor.new { puts A } # => can not access non-shareable objects by non-main Ractor.

# shareable_constant_value: literal
B = {foo: []}
B.frozen? # => true
B[:foo].frozen? # => true

C = [Object.new] # => cannot assign unshareable object to C (Ractor::IsolationError)

D = [Object.new.freeze]
D.frozen? # => true

# shareable_constant_value: experimental_everything
E = Set[1, 2, Object.new]
E.frozen? # => true
E.all(&:frozen?) # => true

Die Direktive beeinflusst nur nachfolgende Konstanten und nur für den aktuellen Geltungsbereich.

module Mod
  # shareable_constant_value: literal
  A = [1, 2, 3]
  module Sub
    B = [4, 5]
  end
end

C = [4, 5]

module Mod
  D = [6]
end
p Mod::A.frozen?, Mod::Sub::B.frozen? # => true, true
p C.frozen?, Mod::D.frozen? # => false, false