### Ruby Module and Class Definitions Source: https://github.com/shopify/rubydex/blob/main/docs/architecture.md Example demonstrating multiple definitions of the same class across different files. ```ruby # foo.rb module Foo class Bar; end end # other_foos.rb class Foo::Bar; end class Foo::Bar; end ``` -------------------------------- ### Constant Resolution Examples Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Provides examples of how Ruby resolves constants based on explicit paths, lexical scope, and ancestor chains. This helps in understanding the order and logic of constant lookups. ```ruby module Foo class Bar ::Bar # Resolves to top-level Bar (if it exists) ::Baz # Resolves to top-level Baz (if it exists) String # Searches: Foo::Bar::String, Foo::String, ::String ::Object # Resolves to top-level Object end end class Bar ::Foo::Bar # Explicit path to Foo::Bar end ``` -------------------------------- ### Ruby Inheritance Chain Resolution Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates the order in which Ruby builds the ancestor chain for a class, including prepended and included modules. ```ruby module PrependedInPrepended end module Prepended prepend PrependedInPrepended end module PrependedInIncluded prepend PrependedInPrepended end module IncludedInIncluded end module Included include IncludedInIncluded end class Foo end class Bar < Foo prepend Prepended include Included end puts Bar.ancestors.to_s #=> [PrependedInPrepended, Prepended, Bar, Included, IncludedInIncluded, Foo, Object, Kernel, BasicObject] ``` -------------------------------- ### MCP Server: Install Rubydex Binary Source: https://github.com/shopify/rubydex/blob/main/README.md Installs the Rubydex MCP server binary using Cargo. This is the first step to enabling AI assistants to query your Ruby codebase. ```bash cargo install --path rust/rubydex-mcp ``` -------------------------------- ### Ruby Global Variables Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates the definition and global accessibility of global variables, indicated by the '$' sigil. ```ruby $foo = 1 class Foo $bar = 2 end ``` -------------------------------- ### Ruby Include Mixin Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates the `include` method, which inserts a module into the ancestor chain after the class, making its methods and constants available to instances. ```ruby module Foo; end class Bar include Foo end Bar.ancestors # => [Bar, Foo, Object, Kernel, BasicObject] ``` -------------------------------- ### Ruby API: Workspace Indexing and Resolution Source: https://github.com/shopify/rubydex/blob/main/README.md Demonstrates creating a graph, configuring encoding, indexing the workspace or specific files, and resolving semantic information. Use this for initial setup and analysis of a Ruby project. ```ruby # Create a new graph representing the current workspace graph = Rubydex::Graph.new # Configuring graph LSP encoding graph.encoding = "utf16" # Index the entire workspace with all dependencies graph.index_workspace # Or index specific file paths graph.index_all(["path/to/file.rb"]) # Transform the initially collected information into its semantic understanding by running resolution graph.resolve ``` -------------------------------- ### Ruby Prepend Mixin Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows the `prepend` method, which inserts a module into the ancestor chain before the class, giving the module's methods higher precedence. ```ruby module Foo; end class Bar prepend Foo end Bar.ancestors # => [Foo, Bar, Object, Kernel, BasicObject] ``` -------------------------------- ### Ruby Instance Variables Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates the scoping of instance variables, which belong to specific objects or the class itself when defined at the class level. ```ruby @foo = 1 # Top-level instance variable (belongs to
) class Foo @bar = 2 # Class instance variable (belongs to Foo object) def initialize @baz = 3 # Instance variable (belongs to instances of Foo) end end ``` -------------------------------- ### Ruby Extend Mixin Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates the `extend` method, which adds module methods as singleton methods (class methods) to the target class or module. ```ruby module Foo def bar; end end class Baz extend Foo end Baz.bar # Works (class method) Baz.new.bar # NoMethodError (not an instance method) ``` -------------------------------- ### Ruby Class Variables Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how class variables, denoted by '@@', are shared across a class and all its instances. ```ruby class Foo @@bar = 2 # Class variable for Foo def self.bar @@bar end def bar @@bar # Same @@bar accessible in instance methods end end # NOT allowed: # @@foo = 1 # Error: class variable access from toplevel ``` -------------------------------- ### Ruby Multi-Assignment Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates multi-assignment (destructuring) across various variable types including constants, global, instance, and class variables. ```ruby # Constants FOO, BAR::BAZ = 1, 2 # Global variables $foo, $bar, $baz = 1, 2, 3 # Instance variables @foo, @bar = 1, 2 # Class variables @@foo, @@bar = 1, 2 # Mixed with top-level references FOO, BAR::BAZ, ::BAZ = 3, 4, 5 ``` -------------------------------- ### Unresolved Constant Reference Example Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows an example of an unresolved constant reference where the resolution depends on the defined constants and the lexical scope chain. This highlights potential ambiguity in constant lookup. ```ruby module Foo BAR # Could be Foo::BAR or top-level BAR - depends on what exists end ``` -------------------------------- ### Ruby Reopening Classes and Modules Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates that classes and modules in Ruby can be reopened and defined multiple times. This example shows three separate definitions and two distinct declarations. ```ruby module Foo class Bar; end end class Foo::Bar; end ``` -------------------------------- ### Get Owner of Class#new Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that the `new` method is defined on the `Class` class itself. ```ruby Class.instance_method(:new).owner # => Class ``` -------------------------------- ### Ruby Namespace Qualification Context Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates how unqualified names refer to different entities based on the current scope. Unqualified names resolve relative to the current namespace, while names starting with '::' are always top-level. ```ruby class Bar # Top-level Bar end module Foo class Bar # Foo::Bar end puts Bar # Inside Foo, "Bar" means "Foo::Bar" end puts Bar # Outside Foo, "Bar" means "Bar" (top-level) ``` -------------------------------- ### Ruby Class Definition with Nested Class Source: https://github.com/shopify/rubydex/blob/main/docs/architecture.md Example illustrating how a nested class definition might be misinterpreted without proper constant resolution. ```ruby module Bar; end class Foo class Bar::Baz; end end ``` -------------------------------- ### Ruby Fully Qualified Name Resolution Rules Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates how Ruby resolves names based on the current scope. Names starting with '::' are top-level, while others are resolved relative to the current namespace. ```ruby class Bar; end class Qux; end module Foo class Bar; end # Defines Foo::Bar # "Bar" => "Foo::Bar" # "::Bar" => "Bar" (top-level) class Baz class Qux; end # Defines Foo::Baz::Qux # "Bar" => "Foo::Bar" # "Qux" => "Foo::Baz::Qux" # "::Qux" => "Qux" (top-level) end end ``` -------------------------------- ### Ruby Singleton and Instance Methods Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates the definition of instance methods and singleton (class) methods within a Ruby class. ```ruby class Foo def bar; end # Instance method def self.baz; end # Singleton method (class method) end ``` -------------------------------- ### Ruby API: Analyzing Require Paths Source: https://github.com/shopify/rubydex/blob/main/README.md Illustrates how to resolve specific require paths and retrieve all indexed require paths. Use this to understand and query module dependencies. ```ruby # Analyzing require paths graph.resolve_require_path("rails/engine", load_paths) # => document pointed by `rails/engine` graph.require_paths(load_paths) # => array of all indexed require paths ``` -------------------------------- ### Multiple Mixins in Ruby Class Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how to include and prepend multiple modules in a single class definition. The order of inclusion/prepending matters for method resolution. ```ruby class Foo include Bar, Baz # Baz is included first, then Bar prepend Qux, Quux # Quux is prepended first, then Qux end ``` -------------------------------- ### Ruby Forward Parameters Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how to use the forward-to-parentheses operator (...) to capture and forward all arguments (positional, keyword, and block) to another method. ```ruby def foo(...) # Forwards all arguments to bar bar(...) end ``` -------------------------------- ### Nested Singleton Classes Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Explains and demonstrates nested singleton classes, showing how `self` changes with each nesting level. ```ruby class Foo class << self # self is now Foo.singleton_class def on_foo_singleton; end class << self # self is now Foo.singleton_class.singleton_class def on_singleton_singleton; end end end end # on_foo_singleton is callable on Foo Foo.on_foo_singleton # on_singleton_singleton is NOT callable on Foo Foo.on_singleton_singleton # => NoMethodError # It's callable on Foo's singleton class Foo.singleton_class.on_singleton_singleton ``` -------------------------------- ### Reopen Singleton Class Explicitly Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how to reopen and add methods to an existing class's singleton class using `class << ClassName`. ```ruby # file: foo.rb class Foo; end # file: foo_singleton.rb class << Foo def bar! puts "bar" end end # file: my_class.rb class MyClass # This also reopens Foo's singleton class class << Foo def baz! puts "baz" end end end Foo.bar! Foo.baz! ``` -------------------------------- ### Define Singleton Behavior Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates defining singleton behavior using `class << self`, `def self.*`, and class instance variables. ```ruby class Foo class << self # reopens (or creates) Foo's singleton class A = 1 def bar; A; end end def self.baz; end # adds the method to Foo's singleton class @ivar = 1 # assigns a class instance variable on Foo's singleton class (NOT a class variable) end ``` -------------------------------- ### MCP Server: Manual Configuration (.mcp.json) Source: https://github.com/shopify/rubydex/blob/main/README.md Manually configures the Rubydex MCP server by creating a .mcp.json file in the project root. This specifies the command to run the server. ```json { "mcpServers": { "rubydex": { "command": "/Users/user/.cargo/bin/rubydex_mcp" } } } ``` -------------------------------- ### Extend vs Include in Singleton Class Hooks Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates the difference in hook calls between `extend Foo` and `include Foo` within a singleton class. `extend` triggers the `extended` hook, while `include` in the singleton class triggers the `included` hook. ```ruby module Foo def self.included(base) puts "included hook called on #{base}" end def self.extended(base) puts "extended hook called on #{base}" end end class UsingExtend extend Foo # Triggers: "extended hook called on UsingExtend" end class UsingSingletonInclude class << self include Foo # Triggers: "included hook called on #" end end ``` -------------------------------- ### Ruby API: Querying Declarations and References Source: https://github.com/shopify/rubydex/blob/main/README.md Demonstrates querying for declarations by name, searching by name, and resolving constant references based on nesting. Essential for finding specific code elements. ```ruby # Querying graph["Foo"] # Get declaration by fully qualified name graph.search("Foo#b") # Name search graph.resolve_constant("Bar", ["Foo", "Baz::Qux"]) # Resolve constant reference based on nesting ``` -------------------------------- ### Ruby Method Aliasing with `alias_method` Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how to create method aliases at runtime using the `alias_method` from the `Module` class. Requires symbols or strings. ```ruby class Foo def bar; end alias_method :baz, :bar # symbol syntax alias_method "qux", "bar" # string syntax end ``` -------------------------------- ### Ruby Constant Alias Creation Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates creating a constant alias by assigning one constant to reference another. ```ruby module Foo CONST = 123 end ALIAS = Foo ALIAS::CONST # Resolves to Foo::CONST (123) ``` -------------------------------- ### Ruby Method Aliasing with `alias` Keyword Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates creating a method alias using the `alias` keyword in Ruby. This can be done with symbols or bare method names. ```ruby class Foo def bar "bar" end alias baz bar # baz is now an alias for bar end ``` ```ruby class Foo def original; end alias :new_name :original # symbol syntax alias another_name original # bare name syntax end ``` -------------------------------- ### Ruby Compact Namespace Notation Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how to use compact notation like 'class Foo::Bar' to create multiple nested levels in a single declaration. Note that '::' resets the namespace to the top level. ```ruby class Foo::Bar class Baz::Qux; end class ::Quuux; end end ``` -------------------------------- ### Ruby API: Inspecting Declarations Source: https://github.com/shopify/rubydex/blob/main/README.md Shows how to access details of a declaration, including its name, definitions, and owner. For namespace declarations, it also demonstrates accessing members, singleton class, ancestors, and descendants. ```ruby # Declarations declaration = graph["Foo"] # All declarations include declaration.name declaration.unqualified_name declaration.definitions declaration.owner # Namespace declarations include declaration.member("bar()") declaration.member("@ivar") declaration.singleton_class declaration.ancestors declaration.descendants ``` -------------------------------- ### Protected Method Cross-Instance Access Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates how protected methods can be called on other instances of the same class. This is a key difference from private methods. ```ruby class Account def initialize(balance) @balance = balance end def >(other) balance > other.balance # works — other is also an Account end protected def balance; @balance; end end a = Account.new(100) b = Account.new(50) a > b # => true (cross-instance protected call succeeds) ``` -------------------------------- ### Ruby Explicit Constant Path Resolution Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates using explicit qualified constant paths to resolve constants, ensuring left-to-right resolution. ```ruby module Foo class Bar Object::String # Explicit path: Object must exist, then String within it end end ``` -------------------------------- ### Top-Level Mixins in Ruby Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates including a module at the top level, which makes its methods available globally via the `Object` class. Attempts to use `include self`, `prepend self`, or `extend self` at the top level result in errors. ```ruby include Foo # Makes Foo's methods available everywhere ``` ```ruby include self # => TypeError: wrong argument type Object (expected Module) prepend self # => NoMethodError: undefined method 'prepend' for main extend self # => TypeError: wrong argument type Object (expected Module) ``` -------------------------------- ### Ruby API: Inspecting Documents and Definitions Source: https://github.com/shopify/rubydex/blob/main/README.md Illustrates how to access document URIs and the definitions found within them, as well as details of individual definitions like location, comments, and deprecation status. ```ruby # Documents document = graph.documents.first document.uri document.definitions # => list of definitions discovered in this document # Definitions definition = declaration.definitions.first definition.location definition.comments definition.name definition.deprecated? definition.name_location ``` -------------------------------- ### Ruby API: Inspecting Locations Source: https://github.com/shopify/rubydex/blob/main/README.md Demonstrates how to access the path information from a location object. This is useful for pinpointing the source file of a code element. ```ruby # Locations location = definition.location location.path ``` -------------------------------- ### MCP Server: Add Rubydex to Project Scope Source: https://github.com/shopify/rubydex/blob/main/README.md Adds the Rubydex MCP server to your project's scope using the Claude CLI. This allows Claude to semantically query the project. ```bash claude mcp add --scope project rubydex " /Users/user/.cargo/bin/rubydex_mcp" ``` -------------------------------- ### Ruby Method Parameter Types Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates the various types of parameters that can be defined in a Ruby method signature, including positional, default, rest, post, keyword, and block parameters. ```ruby def method_name( a, # Required positional parameter b = 42, # Optional positional parameter (with default) *c, # Rest positional parameter (splat) d, # Post parameter (required positional after rest) e:, # Required keyword parameter f: 42, # Optional keyword parameter (with default) **g, # Rest keyword parameter (double splat) &h # Block parameter ) end ``` ```ruby def foo(a, b = 42, *c, d, e:, g: 42, **i, &j); end ``` -------------------------------- ### Ruby API: Querying Diagnostics and Declarations Source: https://github.com/shopify/rubydex/blob/main/README.md Shows how to retrieve diagnostics and iterate over various types of declarations and references within the analyzed graph. Useful for inspecting analysis results and code structure. ```ruby # Get all diagnostics acquired during the analysis graph.diagnostics # Iterating over graph nodes graph.declarations graph.documents graph.constant_references graph.method_references ``` -------------------------------- ### Access Methods on Anonymous Class Instance Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates accessing a class method and an instance method on an anonymous class that is not assigned to a constant. ```ruby c = Class.new do def self.foo; end def bar; end end c.foo c.new.bar ``` -------------------------------- ### Top-Level Constant References Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Explains how constants prefixed with `::` are resolved by searching the ancestors of `Object`, allowing access to constants defined in `Kernel` or modules included into `Object`. This is crucial for understanding global constant resolution. ```ruby module Kernel FOO = 1 end module Foo ::FOO # Found through Object's ancestors (Kernel) ::Bar # Always defined through the ancestors of `Object` Baz # Could be defined in `Foo` or in the ancestors of `Object` end ``` -------------------------------- ### Singleton Scope and Constant Lookup Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates how `self` behaves within a class body and `class << self` blocks, and the difference in constant lookup. ```ruby class Foo @counter = 0 class << self A = 1 def bar @counter += 1 # valid: singleton ivar puts A # valid: constant defined in this singleton scope end end def self.baz puts @counter # valid: reads the singleton's @counter puts A # NameError: Foo::A is not defined end end ``` -------------------------------- ### Ruby API: Inspecting Diagnostics Source: https://github.com/shopify/rubydex/blob/main/README.md Shows how to retrieve details about diagnostics, including the rule violated, the error message, and its location in the codebase. Essential for understanding analysis errors. ```ruby # Diagnostics diagnostic = graph.diagnostics.first diagnostic.rule diagnostic.message diagnostic.location ``` -------------------------------- ### Protected Access Between Unrelated Classes Sharing a Module Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Explains and demonstrates how protected methods work between unrelated classes if they share a common module in their ancestor chain. ```ruby module HasBalance protected def balance; @balance; end end class Account include HasBalance def initialize(balance) = @balance = balance def >(other) = balance > other.balance end class Wallet include HasBalance def initialize(balance) = @balance = balance def >(other) = balance > other.balance end Account.new(100) > Account.new(50) # => true (same class) Wallet.new(100) > Account.new(50) # => true (unrelated classes, but both include HasBalance) ``` -------------------------------- ### Ruby Singleton Method Naming Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that singleton methods (class methods) can share names with instance methods. They coexist because they operate on different receivers. ```ruby class Foo def bar; end # Instance method Foo#bar def self.bar; end # Singleton method Foo.bar (or Foo::bar) end ``` -------------------------------- ### Instance vs Class Variables: Receiver vs Lexical Scoping Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates the difference in scoping for instance variables (receiver-based) and class variables (lexical scope) when defined within methods with explicit receivers. ```ruby class Foo; end class Bar # This defines a singleton method on Foo, but lexically inside Bar def Foo.demo @ivar = "instance var" # Belongs to (the receiver) @@cvar = "class var" # Belongs to Bar (lexical scope) end end Foo.demo Foo.instance_variables # => [:@ivar] Bar.instance_variables # => [] Foo.class_variables # => [] Bar.class_variables # => [:@@cvar] ``` ```ruby class Foo; end class Bar class << Foo def another_demo @ivar2 = 1 # Belongs to Foo (receiver is Foo's singleton) @@cvar2 = 2 # Belongs to Bar (lexical scope) end end end Foo.another_demo Foo.instance_variables # => [:@ivar2] Bar.class_variables # => [:@@cvar2] ``` -------------------------------- ### Define Class Methods and Instance Methods in Anonymous Class Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Defines a class method `foo` and an instance method `bar` (aliased as `baz`) on an anonymous class assigned to a constant `Foo`. ```ruby Foo = Class.new do def self.foo; end # class method on Foo def bar; end # instance method on Foo instances alias_method :baz, :bar end ``` -------------------------------- ### Ruby Global Variable Aliasing Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates how the `alias` keyword can be used to create aliases for global variables in Ruby, allowing them to share the same value. ```ruby $foo = 123 alias $bar $foo # $bar is now an alias for $foo $bar # => 123 $bar = 456 $foo # => 456 (they share the same value) ``` -------------------------------- ### Rust Development Commands Source: https://github.com/shopify/rubydex/blob/main/CONTRIBUTING.md Common Cargo commands for building, linting, and testing Rust code within the workspace. Ensure Rust Analyzer is configured for interactive debugging. ```bash cargo test ``` ```bash cargo clippy ``` ```bash rustfmt ``` ```bash cargo build ``` -------------------------------- ### Ruby Multiple Attribute Methods Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that attribute methods like `attr_accessor` can accept multiple symbols to define multiple attributes simultaneously. ```ruby class Foo attr_accessor :bar, :baz end ``` -------------------------------- ### Cyclic Mixins in Ruby Modules Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that `include self` and `prepend self` are disallowed within modules to prevent cyclic dependencies. `extend self` is permitted. ```ruby module Foo include self # => ArgumentError: cyclic include detected end module Bar prepend self # => ArgumentError: cyclic prepend detected end ``` -------------------------------- ### Instance Variables in Anonymous Class Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how instance variables behave within an anonymous class definition, including class instance variables and instance variables for instances of the class. ```ruby Foo = Class.new do @class_ivar = 1 # instance variable of the Foo class def initialize @ivar = 2 # instance variable of Foo instances end end ``` -------------------------------- ### Define Nested Classes/Constants Under Anonymous Class Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows methods to define classes or constants that are correctly nested under the anonymous class, using `class self::Baz` or `self::Baz = Class.new`. ```ruby class Foo Bar = Class.new do class self::Baz; end # defines Foo::Bar::Baz self::Qux = Class.new # defines Foo::Bar::Qux end end # or class Foo Bar = Class.new Bar::Baz = Class.new end ``` -------------------------------- ### Ruby Constant Resolution Through Inheritance Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how constants are resolved by searching the ancestor chain, with included modules taking precedence over parent classes. ```ruby class Parent CONST = "from parent" end class Child < Parent def show CONST # Resolves to Parent::CONST through inheritance end end Child.new.show # => "from parent" ``` -------------------------------- ### Handle `private` Method on Module Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md The `private` method itself is private on `Module`. Use `send` to bypass visibility checks when calling it. ```ruby class Foo def foo; end private :foo end Foo.private(:foo) # => NoMethodError: private method 'private' called for class Foo Foo.send(:private, :foo) # works (bypasses visibility check) ``` -------------------------------- ### Ruby Chained Constant Aliases Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows how constant aliases can reference other aliases, forming resolution chains. ```ruby module Foo CONST = 123 end ALIAS1 = Foo ALIAS2 = ALIAS1 ALIAS2::CONST # Resolves through ALIAS2 -> ALIAS1 -> Foo -> Foo::CONST ``` -------------------------------- ### Ruby Basic Attribute Methods Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows the usage of `attr_accessor`, `attr_reader`, and `attr_writer` for automatically creating getter and setter methods within a class definition. These are not allowed at the top level. ```ruby class Foo attr_accessor :foo # Creates both `foo` and `foo=` methods attr_reader :bar # Creates only `bar` method (getter) attr_writer :baz # Creates only `baz=` method (setter) end # NOT allowed: # attr_accessor :top_level # Error: undefined method `attr_accessor' ``` -------------------------------- ### Alias_method Copies Source Method Visibility Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that `alias_method` behaves identically to `alias` regarding visibility, copying the source method's visibility at the time of aliasing. This ensures consistent alias behavior. ```ruby class Foo def foo; end private alias_method :bar, :foo # bar is PUBLIC (same behavior as alias) end Foo.public_instance_methods(false) # => [:bar, :foo] Foo.private_instance_methods(false) # => [] ``` -------------------------------- ### Ruby Top-Level Constant Resolution Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Explains that top-level constants are resolved because the main script context ('
') is an instance of Object. ```ruby String # Works because
is Object. Resolved through inheritance ``` -------------------------------- ### Class Variables vs. Singleton Classes Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that class variables bypass singleton classes and always belong to the base class or module. ```ruby class Foo @@in_class_body = 1 class << self @@in_singleton_scope = 2 def set_var @@in_method = 3 end end end Foo.set_var # All class variables belong to Foo, not its singleton class Foo.class_variables # => [:@@in_class_body, :@@in_singleton_scope, :@@in_method] Foo.singleton_class.class_variables # => [:@@in_class_body, :@@in_singleton_scope, :@@in_method] # inherited view # The singleton class itself owns no class variables Foo.singleton_class.class_variables(false) # => [] ``` -------------------------------- ### Ruby Scoped Constant Alias Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates defining a constant alias within a namespace, creating a scoped alias. ```ruby module Foo CONST = 1 end module Bar MyFoo = Foo # Bar::MyFoo is an alias for Foo end Bar::MyFoo::CONST # Resolves to Foo::CONST ``` -------------------------------- ### Define Constants Under Anonymous Class Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates how to define constants that are attached to the anonymous class using `self::CONST`. ```ruby Foo = Class.new do self::CONST = 2 end Foo::CONST ``` -------------------------------- ### Ruby Module Fallback Constant Resolution Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that module fallback searches the full ancestor chain of Object, not just Object directly, to resolve constants. ```ruby module Kernel FOO = 1 end module Bar FOO # Resolves through Object's ancestors (Kernel) end ``` -------------------------------- ### Ruby Development Commands Source: https://github.com/shopify/rubydex/blob/main/CONTRIBUTING.md Rake tasks and RuboCop commands for compiling, testing, linting, and formatting the Ruby gem. These commands also trigger the compilation of Rust crates. ```bash bundle exec rake compile ``` ```bash bundle exec rake ruby_test ``` ```bash bundle exec rubocop ``` ```bash bundle exec rubocop -a ``` -------------------------------- ### Common Pattern: `private_class_method :new` for Singletons Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md A common use case for `private_class_method` is to prevent direct instantiation, enforcing creation through a factory method like `create`. ```ruby class Singleton private_class_method :new def self.create; new; end # internal access works end Singleton.new # => NoMethodError Singleton.create # => # ``` -------------------------------- ### Singleton Method Visibility in `class << self` Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that visibility modifiers work normally within `class << self` blocks for defining singleton methods. ```ruby class Foo class << self private def bar; end # Actually private end end Foo.bar # private method 'bar' called for class Foo (NoMethodError) ``` -------------------------------- ### Ruby Conditional Constant Alias with ||= Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates using the ||= operator to create conditional constant aliases, assigning only if the alias is not already defined. ```ruby ALIAS ||= Foo # Only assigns if ALIAS is not already defined ``` -------------------------------- ### Ruby Constant Resolution with Included Modules Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that when a constant is defined in both an included module and a parent class, the included module's constant takes precedence. ```ruby module M CONST = "from module" end class Parent CONST = "from parent" end class Child < Parent include M def show CONST # Resolves to M::CONST (included module takes precedence) end end ``` -------------------------------- ### Ruby attr Method: Reader and Writer (True Parameter) Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Creates both a reader (getter) and a writer (setter) for the specified attribute when the second parameter is `true`. ```ruby class Foo attr :foo, true # Creates both foo and foo= (getter and setter) end ``` -------------------------------- ### Ruby Top-Level Method Aliasing Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates that only the `alias` keyword can be used for creating top-level method aliases in Ruby. `alias_method` will raise a `NoMethodError`. ```ruby def foo; end alias bar foo # Creates top-level method alias alias_method :bar, :foo # NoMethodError ``` -------------------------------- ### Aliases Do Not Track Later Visibility Changes Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates that aliases do not track subsequent visibility changes to the original method. The alias retains the visibility it had at the time of its creation. ```ruby class Foo def foo; end alias bar foo # bar is public (same as foo at this point) private :foo # foo becomes private end Foo.public_instance_methods(false) # => [:bar] Foo.private_instance_methods(false) # => [:foo] ``` -------------------------------- ### Retroactively Make Methods Private Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Use `private`, `protected`, or `public` with a method name symbol to change its visibility after definition. This works across reopened classes. ```ruby class Foo def foo; end def bar; end private :foo # retroactively makes foo private end Foo.public_instance_methods(false) # => [:bar] Foo.private_instance_methods(false) # => [:foo] ``` ```ruby class Foo; def foo; end; end class Foo; private :foo; end # works — retroactive across reopen Foo.private_instance_methods(false) # => [:foo] ``` -------------------------------- ### Namespace Nesting in Anonymous Classes Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Explains that `class`/`module` definitions inside an anonymous class block do not introduce new lexical nesting for namespaces. ```ruby class Foo Bar = Class.new do class Baz; end end end # Baz is Foo::Baz, not Foo::Bar::Baz ``` -------------------------------- ### Private Constant Availability at Top Level Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that `private_constant` and `public_constant` are not available at the top level because `self` is `main`, not a Module. These methods should only be called on Modules. ```ruby private_constant :FOO # => NoMethodError: undefined method 'private_constant' for main public_constant :FOO # => NoMethodError: undefined method 'public_constant' for main ``` -------------------------------- ### Constant Visibility and Inheritance Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates that private constants block external access but not internal or inherited access. Use this to manage access to constants within class hierarchies. ```ruby class Parent CONST = 1 private_constant :CONST def use_const; CONST; end end class Child < Parent def try_const; CONST; end end Parent.new.use_const # => 1 (internal access works) Child.new.try_const # => 1 (inherited access through method works) Child::CONST # => NameError (direct external access blocked) ``` -------------------------------- ### Explicit Method Visibility Modifiers in Ruby Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates the use of `public`, `private`, and `protected` visibility modifiers within a Ruby class to control method accessibility. `protected` is not available at the top level. ```ruby class Foo def m1; end # public (default) private def m2; end # private (after modifier) protected def m3; end # protected (inline modifier) end ``` -------------------------------- ### Private Method Cross-Instance Access Failure Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates that private methods cannot be called on other instances, even within the same class, when an explicit receiver is used. ```ruby class Wallet def initialize(amount) @amount = amount end def >(other) amount > other.amount # NoMethodError — private method called on other end private def amount; @amount; end end ``` -------------------------------- ### Private Constants in Included Modules Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that private constants from included modules are also blocked from external access. This ensures encapsulation within the including class. ```ruby module Mod CONST = 1 private_constant :CONST end class Foo; include Mod; end Foo::CONST # => NameError ``` -------------------------------- ### Top-Level Constant References in BasicObject Subclass Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that top-level constant references (`::FOO`) resolve through `Object`'s ancestors even within classes that inherit from `BasicObject`, which lacks standard inheritance chains. This confirms the behavior of `::` resolution. ```ruby module Kernel FOO = 1 end class Bar < BasicObject ::FOO # Resolves through Object's ancestors, not through Bar's end ``` -------------------------------- ### Singleton Method Visibility Ignored Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that visibility modifiers have no effect on singleton methods defined with `def self.method`. These methods remain public by default. ```ruby class Foo private def self.bar; end # STILL PUBLIC (visibility ignored) # private_class_method :bar can turn `bar` private end Foo.bar # Works fine ``` -------------------------------- ### Alias Copies Source Method Visibility Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that `alias` copies the source method's visibility at the time of aliasing, ignoring the current visibility stack. Use this to understand how method aliases inherit visibility. ```ruby class Foo def pub; end # public private alias copy pub # copy is PUBLIC (copies source, ignores stack) end Foo.public_instance_methods(false) # => [:copy, :pub] Foo.private_instance_methods(false) # => [] ``` -------------------------------- ### Ruby attr Method: Multiple Attributes (No Parameter) Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Creates only readers (getters) for multiple attributes when no second parameter is provided. ```ruby class Foo attr :foo, :bar, :baz # Creates only: foo, bar, baz (readers only) attr :a, "b", "c" # Creates only: a, b, c (readers only) end ``` -------------------------------- ### Instance Variables in Singleton Classes Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Highlights that instance variables defined in class scope belong to the singleton class, unlike class variables. ```ruby class Foo @class_ivar = 1 # belongs to Foo's singleton class @@class_var = 2 # belongs to Foo itself end ``` -------------------------------- ### Protected Method Call Failure by Unrelated Class Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that an unrelated class cannot call protected methods on an object, even if it has a reference to it. ```ruby class Auditor def inspect_balance(account) account.balance # NoMethodError — Auditor is not in Account's hierarchy end end ``` -------------------------------- ### Inheritance Issues in Anonymous Class Blocks Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates `NameError` when trying to use the assigned constant as a superclass inside the block, as assignment occurs after block execution. ```ruby class Foo Bar = Class.new do class Baz < Bar; end # NameError: uninitialized constant Foo::Bar class Baz < self::Bar; end # NameError: uninitialized constant #::Bar end end ``` -------------------------------- ### Ruby Lexical Nesting with Top-Level References Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that even when using '::' for top-level references, lexical nesting is preserved for constant lookup. This means constants can be resolved from within a lexically nested scope even if the class/module itself is defined at the top level. ```ruby module Foo CONST = 42 class ::Bar CONST # resolves to Foo::CONST because we're inside the `Foo` namespace end end class Bar CONST # NameError because this `Bar` is not lexically inside `Foo` end ``` -------------------------------- ### Protected Access in Subclasses Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that protected access modifiers extend to subclasses, allowing them to call protected methods defined in their ancestors. ```ruby class SavingsAccount < Account def compare(other) balance > other.balance # works — both are in the Account hierarchy end end ``` -------------------------------- ### Ruby Constant Resolution with BasicObject Inheritance Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates that classes inheriting directly from BasicObject cannot resolve top-level constants because Object is not in their ancestor chain. ```ruby class Foo < BasicObject String # NameError: Foo doesn't have Object in its ancestor chain end ``` -------------------------------- ### Ruby Attribute Methods Receiver Context Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Explains that attribute methods in Ruby only work when called on `self`, either implicitly or explicitly. Calls on different receivers are not allowed. ```ruby class Foo attr_accessor :foo # Works (implicit self) self.attr_accessor :qux # Works (explicit self) foo.attr_accessor :ignored # Does NOT work (different receiver) end ``` -------------------------------- ### Ruby Defining Class Under Aliased Path Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that defining a class under an aliased path results in the class being named based on the alias target, not the alias itself. ```ruby class Foo; end ALIAS = Foo class ALIAS::Bar; end ALIAS::Bar.name # Foo::Bar, not ALIAS::Bar ``` -------------------------------- ### Mixin Deduplication in Ruby Ancestor Chain Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Illustrates how Ruby automatically removes duplicate modules from the ancestor chain, ensuring each module appears only once, even if included multiple times directly or indirectly. ```ruby module A; end module B include A end class Foo include A include B end Foo.ancestors # => [Foo, B, A, Object, ...] # A appears only once, not twice ``` ```ruby module A; end module B include A end module C include A end class Foo include B include C end Foo.ancestors # => [Foo, C, B, A] # A appears only once despite being in both B and C ``` ```ruby module A; end module B include A end class Parent include B end class Child < Parent include B end Child.ancestors # => [Child, Parent, B, A, Object, ...] # B and A appear once (child's include is deduplicated against parent) ``` -------------------------------- ### Singleton Class Blocks Inside Anonymous Classes Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Explains that `class << self` blocks inside anonymous classes create lexical scopes, attaching constants to the singleton class. ```ruby Foo = Class.new do class << self CONST = 1 end end Foo.singleton_class.constants # => [:CONST] Foo.constants # => [] ``` -------------------------------- ### Independent Copy with `module_function` Redefinition Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Redefining a method after applying `module_function` creates an independent copy for the singleton method, preserving the original definition. ```ruby module Foo def foo; "v1"; end module_function :foo def foo; "v2"; end # redefines instance method end Foo.foo # => "v1" (singleton is an independent copy of v1) ``` -------------------------------- ### Ruby attr Method: Reader Only (False Parameter) Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Creates only a reader (getter) for the specified attribute when the second parameter is `false`. ```ruby class Foo attr :foo, false # Creates only foo (getter) end ``` -------------------------------- ### Private Constant Targeting Receiver Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates how `private_constant` targets the receiver, not the lexical scope. Use `private_constant` to control constant visibility within a module or class. ```ruby module Bar CONST = 1 class Foo CONST = 2 private_constant(:CONST) # targets Foo::CONST (self is Foo) Bar.private_constant(:CONST) # targets Bar::CONST (explicit receiver) end end Bar::CONST # => NameError (blocked by explicit receiver call) Bar::Foo::CONST # => NameError (blocked by bare call inside Foo) ``` -------------------------------- ### Constants in Nested Anonymous Classes Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates that constants defined in nested anonymous classes are attached to the closest lexical scope, not the outer anonymous class. ```ruby Foo = Class.new do Class.new do CONST = 1 end end # CONST is defined on top-level, the closest lexical scope, instead of Foo defined?(CONST) #=> "constant" defined?(Foo::CONST) #=> nil ``` -------------------------------- ### Error Defining Class Variables in Top-Level Anonymous Class Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Demonstrates the `RuntimeError` that occurs when attempting to define a class variable in a top-level anonymous class. ```ruby Foo = Class.new do @@cvar = 1 # RuntimeError: class variable access from toplevel end ``` -------------------------------- ### Nested Anonymous Classes within Singleton Class Blocks Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Shows that constants defined in anonymous classes within a singleton class block are attached to the singleton class. ```ruby Foo = Class.new do class << self Class.new do CONST = 1 end end end Foo.singleton_class.constants # => [:CONST] ``` -------------------------------- ### Ruby attr Method: Reader Only (No Parameter) Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Creates only a reader (getter) for the specified attribute when no second parameter is provided. ```ruby class Foo attr :foo # Creates only foo (getter) end ``` -------------------------------- ### Make Class Methods Private with `private_class_method` Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Use `private_class_method` to make singleton methods (class methods) private. This can be done directly or inline. ```ruby class Foo def self.hidden; end private_class_method :hidden end Foo.hidden # => NoMethodError: private method 'hidden' called for class Foo ``` ```ruby class Foo private_class_method def self.secret; "secret"; end end Foo.secret # => NoMethodError ``` -------------------------------- ### Extend Self Pattern in Ruby Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Use `extend self` to make module methods callable directly on the module itself. This is useful for creating module-level methods. ```ruby module Foo extend self def bar "bar" end end Foo.bar # => "bar" ``` -------------------------------- ### Implicit Copy with `private :inherited_method` Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Using `private :inherited_method` on a child class creates an implicit copy, making the method private to the child class without affecting the parent. ```ruby class Parent def inherited_method; "parent"; end end class Child < Parent private :inherited_method end Parent.new.respond_to?(:inherited_method) # => true (parent unaffected) Child.new.respond_to?(:inherited_method) # => false (private on child) Child.instance_method(:inherited_method).owner # => Child (NOT Parent!) ``` -------------------------------- ### Make Constants Public with `public_constant` Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Use `public_constant` to reverse the effect of `private_constant`, making a previously private constant accessible again via the `::` operator. ```ruby class Foo CONST = 1 private_constant :CONST public_constant :CONST end Foo::CONST # => 1 (accessible again) ``` -------------------------------- ### Ruby attr Method: Invalid Second Parameter Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Raises a `TypeError` at runtime if the second parameter to `attr` is not a symbol or a string. ```ruby class Foo attr :foo, 123 # Raises `123 is not a symbol nor a string (TypeError)` end ``` -------------------------------- ### Default Method Visibility in Ruby Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Explains that methods defined at the top level default to private, while methods defined within classes or modules default to public. Explicit modifiers can override these defaults. ```ruby def foo; end # private by default at top level public def bar; end # now public (after public modifier) ``` ```ruby class Foo def bar; end # public by default end ``` -------------------------------- ### Retroactive `module_function` Behavior Source: https://github.com/shopify/rubydex/blob/main/docs/ruby-behaviors.md Applying `module_function` with a method name retroactively makes the method a public singleton method while making the instance method private. This is only available within module bodies. ```ruby module Foo def foo; "foo"; end module_function :foo end Foo.foo # => "foo" (public singleton) Foo.public_instance_methods(false) # => [] Foo.private_instance_methods(false) # => [:foo] (instance becomes private) Foo.singleton_methods(false) # => [:foo] ```