Ejemplos Ruby

Ejemplos de código Ruby esenciales para desarrollo web, incluyendo framework Rails y características modernas de Ruby

💻 Hola Mundo Ruby ruby

🟢 simple

Programa Hola Mundo básico con tipado dinámico y sintaxis elegante

⏱️ 12 min 🏷️ ruby, dynamic typing, object-oriented
Prerequisites: Basic programming concepts
# Ruby Hello World Examples

# 1. Basic Hello World
puts "Hello, World!"

# 2. Hello World with variable
message = "Hello, World!"
puts message

# 3. Hello World with method
def say_hello
  "Hello, World!"
end

puts say_hello

# 4. Hello World with parameters
def greet(name)
  "Hello, #{name}!"
end

puts greet("World")
puts greet("Ruby")

# 5. Hello World with class
class Greeter
  def initialize(message = "Hello, World!")
    @message = message
  end

  def greet
    puts @message
  end
end

greeter = Greeter.new
greeter.greet

# 6. Hello World with user input
print "Enter your name: "
name = gets.chomp
puts "Hello, #{name}!"

# 7. Hello World multiple times
5.times do |i|
  puts "Hello, World! #{i + 1}"
end

# 8. Hello World with array
greetings = ["Hello", "Bonjour", "Hola", "Ciao", "こんにちは"]
greetings.each do |greeting|
  puts "#{greeting}, World!"
end

# 9. Hello World with hash
greetings = {
  "en" => "Hello",
  "es" => "Hola",
  "fr" => "Bonjour",
  "de" => "Hallo",
  "ja" => "こんにちは"
}

greetings.each do |lang, greeting|
  puts "#{greeting}, World! (#{lang})"
end

# 10. Hello World with JSON
require 'json'

response = {
  message: "Hello, World!",
  timestamp: Time.now.to_s,
  success: true
}

puts JSON.pretty_generate(response)

# Basic data types examples
# Ruby is dynamically typed, so types are inferred

integer = 42
float = 3.14
string = "Hello, Ruby!"
boolean = true
array = [1, 2, 3, 4, 5]
hash = { name: "John Doe", age: 30, email: "[email protected]" }
symbol = :ruby_symbol
nil_value = nil

puts "Integer: #{integer}, Class: #{integer.class}"
puts "Float: #{float}, Class: #{float.class}"
puts "String: #{string}, Class: #{string.class}"
puts "Boolean: #{boolean}, Class: #{boolean.class}"
puts "Array: #{array}, Class: #{array.class}"
puts "Hash: #{hash}, Class: #{hash.class}"
puts "Symbol: #{symbol}, Class: #{symbol.class}"
puts "Nil: #{nil_value}, Class: #{nil_value.class}"

# Control flow examples
age = 18
if age >= 18
  puts "You are an adult"
else
  puts "You are a minor"
end

# Case statement
grade = 'A'
case grade
when 'A'
  puts "Excellent!"
when 'B'
  puts "Good job!"
when 'C'
  puts "Fair enough"
else
  puts "Need improvement"
end

# Loop examples
fruits = ["apple", "banana", "cherry"]
fruits.each do |fruit|
  puts "I like #{fruit}"
end

# Range operations
(1..10).each do |i|
  puts "Number: #{i}"
end

# Array methods examples
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = numbers.select { |n| n.even? }
squared_numbers = numbers.map { |n| n ** 2 }
sum = numbers.reduce(0, :+)

puts "Even numbers: #{even_numbers}"
puts "Squared numbers: #{squared_numbers}"
puts "Sum: #{sum}"

# String methods examples
text = "Hello, Ruby Programming!"
puts "Upcase: #{text.upcase}"
puts "Downcase: #{text.downcase}"
puts "Capitalized: #{text.capitalize}"
puts "Length: #{text.length}"
puts "Reverse: #{text.reverse}"

# Method chaining
numbers = [1, 2, 3, 4, 5]
result = numbers
  .select { |n| n.even? }
  .map { |n| n ** 2 }
  .reduce(0, :+)

puts "Result of chained operations: #{result}"

# Blocks and Procs
def execute_twice
  yield
  yield
end

execute_twice { puts "Hello from block!" }

# Procs and Lambdas
greet_proc = Proc.new { |name| puts "Hello, #{name}!" }
greet_proc.call("Ruby")

greet_lambda = lambda { |name| "Hello, #{name}!" }
puts greet_lambda.call("Lambda")

# Symbols and their common uses
status = :active
puts status == :active ? "User is active" : "User is inactive"

# Using symbols as hash keys (Rubyist style)
user = {
  name: "Alice",
  age: 25,
  :email => "[email protected]"
}

puts user[:name]
puts user[:email]

# Constants
PI = 3.14159265359
MAX_USERS = 100

puts "PI: #{PI}"
puts "Max users: #{MAX_USERS}"

# Exception handling
begin
  result = 10 / 0
rescue ZeroDivisionError => e
  puts "Error: #{e.message}"
ensure
  puts "This always runs"
end

# Method return values
def add(a, b)
  # Ruby implicitly returns the last evaluated expression
  a + b
end

puts "Addition: #{add(5, 3)}"

# Splat arguments
def sum(*numbers)
  numbers.reduce(0, :+)
end

puts "Sum of 1, 2, 3, 4, 5: #{sum(1, 2, 3, 4, 5)}"

# Keyword arguments (Ruby 2.0+)
def create_user(name:, email:, age: nil, role: 'user')
  {
    name: name,
    email: email,
    age: age,
    role: role
  }
end

user = create_user(name: "Bob", email: "[email protected]", age: 30)
puts "Created user: #{user}"

# Class methods
class MathUtils
  def self.pi
    3.14159265359
  end

  def self.circle_area(radius)
    pi * radius ** 2
  end
end

puts "Pi: #{MathUtils.pi}"
puts "Circle area (radius 5): #{MathUtils.circle_area(5)}"

# Modules and mixins
module Greetable
  def greet
    puts "Hello, I'm #{name}"
  end
end

class Person
  include Greetable
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

person = Person.new("Charlie")
person.greet

💻 Patrones Ruby on Rails ruby

🟡 intermediate ⭐⭐⭐⭐

Patrones comunes de Rails, arquitectura MVC y prácticas modernas de desarrollo web

⏱️ 45 min 🏷️ ruby, rails, web development, patterns
Prerequisites: Ruby basics, Web development concepts, MVC architecture
# Ruby on Rails Patterns Examples

# 1. Model with validations and associations
# app/models/user.rb
class User < ApplicationRecord
  # Validations
  validates :name, presence: true, length: { minimum: 2, maximum: 50 }
  validates :email, presence: true, uniqueness: { case_sensitive: false }
  validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
  validates :age, numericality: { greater_than: 0, less_than: 120 }
  validates :terms_of_service, acceptance: true

  # Callbacks
  before_save :downcase_email
  after_create :send_welcome_email
  after_commit :log_user_creation

  # Associations
  has_many :posts, dependent: :destroy
  has_many :comments, through: :posts
  has_one :profile, dependent: :destroy
  has_and_belongs_to_many :roles
  has_many :followers, class_name: "Follow", foreign_key: "followed_id"
  has_many :followed, class_name: "Follow", foreign_key: "follower_id"

  # Scopes
  scope :active, -> { where(active: true) }
  scope :by_age, ->(min_age, max_age) { where(age: min_age..max_age) }
  scope :recent, -> { order(created_at: :desc) }
  scope :with_posts, -> { includes(:posts).where.not(posts: { id: nil }) }

  # Class methods
  def self.search(query)
    where("name ILIKE ? OR email ILIKE ?", "%#{query}%", "%#{query}%")
  end

  def self.by_role(role_name)
    joins(:roles).where(roles: { name: role_name })
  end

  # Instance methods
  def full_name
    profile&.full_name || name
  end

  def admin?
    roles.exists?(name: 'admin')
  end

  def can_post?
    active? && email_verified?
  end

  def follow(user)
    followed << user unless following?(user)
  end

  def unfollow(user)
    followed.delete(user) if following?(user)
  end

  def following?(user)
    followed.include?(user)
  end

  private

  def downcase_email
    email.downcase!
  end

  def send_welcome_email
    UserMailer.welcome_email(self).deliver_later
  end

  def log_user_creation
    Rails.logger.info "New user created: #{name} (#{email})"
  end
end

# 2. Controller with RESTful actions and strong parameters
# app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :authenticate_user!
  before_action :set_user, only: [:show, :edit, :update, :destroy]
  before_action :authorize_user, only: [:edit, :update, :destroy]

  # GET /users
  def index
    @users = User.includes(:profile)
                .active
                .recent
                .page(params[:page])
                .per(20)

    respond_to do |format|
      format.html
      format.json { render json: @users }
      format.csv { send_data User.to_csv(@users), filename: "users.csv" }
    end
  end

  # GET /users/1
  def show
    @posts = @user.posts.includes(:comments).published.recent.limit(10)

    respond_to do |format|
      format.html
      format.json { render json: @user }
    end
  end

  # GET /users/new
  def new
    @user = User.new
    @user.build_profile
  end

  # POST /users
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, notice: 'User was successfully created.' }
        format.json { render json: @user, status: :created }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # GET /users/1/edit
  def edit
  end

  # PATCH/PUT /users/1
  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to @user, notice: 'User was successfully updated.' }
        format.json { render json: @user }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1
  def destroy
    @user.destroy

    respond_to do |format|
      format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private

  def set_user
    @user = User.includes(:profile, :posts).find(params[:id])
  end

  def authorize_user
    redirect_to root_path, alert: 'Not authorized' unless can?(:manage, @user)
  end

  def user_params
    params.require(:user).permit(
      :name,
      :email,
      :age,
      :bio,
      profile_attributes: [
        :id,
        :first_name,
        :last_name,
        :avatar,
        :website,
        :location,
        :bio
      ]
    )
  end
end

# 3. Service Object Pattern
# app/services/user_registration_service.rb
class UserRegistrationService
  include ActiveModel::Model
  include ActiveModel::Attributes

  attribute :email, :string
  attribute :password, :string
  attribute :password_confirmation, :string
  attribute :name, :string
  attribute :accept_terms, :boolean
  attribute :marketing_emails, :boolean, default: false

  validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
  validates :password, presence: true, length: { minimum: 8 }
  validates :password_confirmation, presence: true
  validates :name, presence: true, length: { minimum: 2 }
  validates :accept_terms, acceptance: true

  validate :passwords_match
  validate :email_uniqueness

  def call
    return false unless valid?

    ActiveRecord::Base.transaction do
      user = User.create!(user_attributes)
      Profile.create!(profile_attributes(user))
      send_welcome_email(user)
      subscribe_to_newsletter(user) if marketing_emails
      user
    end
  rescue ActiveRecord::RecordInvalid => e
    errors.add(:base, e.message)
    false
  end

  private

  def passwords_match
    return if password == password_confirmation
    errors.add(:password_confirmation, "doesn't match Password")
  end

  def email_uniqueness
    return unless User.exists?(email: email)
    errors.add(:email, "has already been taken")
  end

  def user_attributes
    {
      email: email.downcase,
      password: password,
      name: name,
      active: true,
      email_verified: false
    }
  end

  def profile_attributes(user)
    {
      user: user,
      first_name: name.split(' ').first,
      last_name: name.split(' ').last,
      avatar: generate_default_avatar,
      email_notifications: true
    }
  end

  def generate_default_avatar
    # Generate a default avatar using a service like Gravatar
    "https://ui-avatars.com/api/?name=#{URI.encode_www_form_component(name)}&background=random"
  end

  def send_welcome_email(user)
    UserMailer.welcome_email(user).deliver_later
  end

  def subscribe_to_newsletter(user)
    NewsletterSubscription.create!(user: user, active: true)
  end
end

# 4. Decorator Pattern
# app/decorators/user_decorator.rb
class UserDecorator
  include ActionView::Helpers
  include Rails.application.routes.url_helpers

  def initialize(user)
    @user = user
  end

  delegate_missing_to :@user

  def display_name
    if profile&.first_name && profile&.last_name
      "#{profile.first_name} #{profile.last_name}"
    else
      name
    end
  end

  def avatar_url(size: :medium)
    if profile&.avatar.present?
      profile.avatar.variant(resize: avatar_size(size))
    else
      default_avatar_url
    end
  end

  def profile_completion_percentage
    completed_fields = 0
    total_fields = 5

    completed_fields += 1 if name.present?
    completed_fields += 1 if email.present?
    completed_fields += 1 if profile&.bio.present?
    completed_fields += 1 if profile&.location.present?
    completed_fields += 1 if profile&.website.present?

    (completed_fields.to_f / total_fields * 100).round
  end

  def join_date
    created_at.strftime("%B %d, %Y")
  end

  def status_badge
    case
    when admin?
      content_tag(:span, "Admin", class: "badge badge-danger")
    when active?
      content_tag(:span, "Active", class: "badge badge-success")
    else
      content_tag(:span, "Inactive", class: "badge badge-secondary")
    end
  end

  def stats
    {
      posts: posts.published.count,
      comments: comments.count,
      followers: followers.count,
      following: followed.count
    }
  end

  def action_buttons(current_user)
    buttons = []

    if current_user == self
      buttons << link_to("Edit Profile", edit_user_path(self), class: "btn btn-primary")
    else
      if current_user.following?(self)
        buttons << link_to("Unfollow", unfollow_user_path(self), method: :delete, class: "btn btn-secondary")
      else
        buttons << link_to("Follow", follow_user_path(self), method: :post, class: "btn btn-primary")
      end
    end

    buttons.join(" ").html_safe
  end

  private

  def avatar_size(size)
    case size
    when :small then "50x50"
    when :medium then "100x100"
    when :large then "200x200"
    else "100x100"
    end
  end

  def default_avatar_url
    "https://ui-avatars.com/api/?name=#{URI.encode_www_form_component(name)}&background=random&size=100"
  end
end

# 5. Query Object Pattern
# app/queries/post_search_query.rb
class PostSearchQuery
  def initialize(params = {})
    @params = params
  end

  def call
    posts = Post.published.includes(:user, :tags, :comments)
    posts = filter_by_user(posts)
    posts = filter_by_tags(posts)
    posts = filter_by_date_range(posts)
    posts = filter_by_status(posts)
    posts = search_by_content(posts)
    posts = sort_posts(posts)
    posts
  end

  private

  attr_reader :params

  def filter_by_user(posts)
    return posts unless params[:user_id].present?
    posts.where(user_id: params[:user_id])
  end

  def filter_by_tags(posts)
    return posts unless params[:tag_ids].present?
    posts.joins(:tags).where(tags: { id: params[:tag_ids] })
  end

  def filter_by_date_range(posts)
    if params[:date_from].present?
      posts = posts.where("posts.created_at >= ?", params[:date_from])
    end

    if params[:date_to].present?
      posts = posts.where("posts.created_at <= ?", params[:date_to])
    end

    posts
  end

  def filter_by_status(posts)
    return posts unless params[:status].present?
    posts.where(status: params[:status])
  end

  def search_by_content(posts)
    return posts unless params[:query].present?
    posts.where(
      "posts.title ILIKE ? OR posts.content ILIKE ?",
      "%#{params[:query]}%",
      "%#{params[:query]}%"
    )
  end

  def sort_posts(posts)
    sort_column = params[:sort] || 'created_at'
    sort_direction = params[:direction] || 'desc'

    if posts.column_names.include?(sort_column)
      posts.order("#{sort_column} #{sort_direction}")
    else
      posts.order(created_at: :desc)
    end
  end
end

# 6. Form Object Pattern
# app/forms/post_form.rb
class PostForm
  include ActiveModel::Model
  include ActiveModel::Attributes
  include ActiveModel::Validations::Callbacks

  attribute :title, :string
  attribute :content, :string
  attribute :excerpt, :string
  attribute :status, :string, default: 'draft'
  attribute :published_at, :datetime
  attribute :tag_names, :string, default: ''
  attribute :featured_image, :string
  attribute :user_id, :integer

  validates :title, presence: true, length: { maximum: 100 }
  validates :content, presence: true, length: { minimum: 50 }
  validates :status, inclusion: { in: %w[draft published archived] }
  validates :user_id, presence: true

  validate :published_at_presence_if_published
  validate :tag_names_validity

  before_validation :generate_excerpt_if_blank
  before_validation :set_published_at

  def initialize(post = nil, attributes = {})
    @post = post
    super(attributes)
    copy_post_attributes if @post
  end

  def save
    return false unless valid?

    ActiveRecord::Base.transaction do
      post = @post || user.posts.build
      post.assign_attributes(post_attributes)
      post.save!
      update_post_tags(post)
      @post = post
    end

    true
  rescue ActiveRecord::RecordInvalid => e
    errors.add(:base, e.message)
    false
  end

  def persisted?
    @post&.persisted?
  end

  private

  attr_reader :post

  def user
    User.find(user_id) if user_id.present?
  end

  def post_attributes
    {
      title: title,
      content: content,
      excerpt: excerpt,
      status: status,
      published_at: published_at,
      featured_image: featured_image
    }
  end

  def copy_post_attributes
    self.title = @post.title
    self.content = @post.content
    self.excerpt = @post.excerpt
    self.status = @post.status
    self.published_at = @post.published_at
    self.featured_image = @post.featured_image
    self.user_id = @post.user_id
    self.tag_names = @post.tags.map(&:name).join(', ')
  end

  def published_at_presence_if_published
    return unless status == 'published'
    errors.add(:published_at, "can't be blank when status is published") if published_at.blank?
  end

  def tag_names_validity
    return if tag_names.blank?

    invalid_tags = tag_names.split(',').map(&:strip).reject { |name| name.match?(/A[a-zA-Z0-9s-]+z/) }
    if invalid_tags.any?
      errors.add(:tag_names, "contain invalid tags: #{invalid_tags.join(', ')}")
    end
  end

  def generate_excerpt_if_blank
    return if excerpt.present?
    self.excerpt = content&.truncate(150, separator: ' ')
  end

  def set_published_at
    self.published_at = Time.current if status == 'published' && published_at.blank?
  end

  def update_post_tags(post)
    tag_names_array = tag_names.split(',').map(&:strip).map(&:downcase).uniq
    current_tag_names = post.tags.map(&:name)

    # Remove tags that are no longer present
    tags_to_remove = current_tag_names - tag_names_array
    post.tags.where(name: tags_to_remove).destroy_all if tags_to_remove.any?

    # Add new tags
    tag_names_array.each do |tag_name|
      next if current_tag_names.include?(tag_name)
      post.tags.find_or_create_by(name: tag_name)
    end
  end
end

# 7. Background Job Pattern
# app/jobs/email_notification_job.rb
class EmailNotificationJob < ApplicationJob
  queue_as :default

  rescue_from(StandardError) do |exception|
    Rails.logger.error "Email job failed: #{exception.message}"
    retry_job wait: 5.minutes, attempts: 3
  end

  def perform(user_id, template, **options)
    user = User.find(user_id)
    UserMailer.with(user: user, **options).send(template).deliver_now
  end
end

# 8. Policy Pattern for Authorization
# app/policies/post_policy.rb
class PostPolicy
  attr_reader :user, :post

  def initialize(user, post)
    @user = user
    @post = post
  end

  def index?
    true
  end

  def show?
    post.published? || (user && (user.admin? || user == post.user))
  end

  def create?
    user.present? && user.can_post?
  end

  def update?
    user.present? && (user.admin? || user == post.user)
  end

  def destroy?
    user.present? && (user.admin? || user == post.user)
  end

  def publish?
    user.present? && (user.admin? || (user == post.user && user.can_post?))
  end

  class Scope
    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      if user&.admin?
        scope.all
      elsif user.present?
        scope.where("published = ? OR user_id = ?", true, user.id)
      else
        scope.where(published: true)
      end
    end

    private

    attr_reader :user, :scope
  end
end

# Example usage in controller:
# def index
#   @posts = policy_scope(Post)
#   @posts = PostSearchQuery.new(params).call
# end

# def show
#   authorize @post
# end

💻 Metaprogramación Ruby ruby

🔴 complex ⭐⭐⭐⭐⭐

Técnicas avanzadas de metaprogramación, métodos dinámicos y métodos mágicos de Ruby

⏱️ 50 min 🏷️ ruby, metaprogramming, advanced, dynamic
Prerequisites: Advanced Ruby, Object-oriented Ruby, Ruby introspection
# Ruby Metaprogramming Examples

# 1. Dynamic method definition
class DynamicMethods
  def self.create_methods(*method_names)
    method_names.each do |name|
      define_method(name) do |arg|
        "Called method #{name} with argument: #{arg}"
      end
    end
  end
end

DynamicMethods.create_methods(:foo, :bar, :baz)

obj = DynamicMethods.new
puts obj.foo("hello")
puts obj.bar("world")
puts obj.baz("ruby")

# 2. method_missing for dynamic method calls
class DynamicAccessor
  def initialize(data = {})
    @data = data
  end

  def method_missing(method_name, *args, &block)
    if method_name.to_s.end_with?('=')
      # Setter method
      key = method_name.to_s.chomp('=').to_sym
      @data[key] = args.first
    else
      # Getter method
      key = method_name.to_sym
      if @data.key?(key)
        @data[key]
      else
        super
      end
    end
  end

  def respond_to_missing?(method_name, include_private = false)
    method_name.to_s.end_with?('=') || @data.key?(method_name.to_sym) || super
  end
end

accessor = DynamicAccessor.new
accessor.name = "John"
accessor.age = 30

puts accessor.name
puts accessor.age

# 3. Class-level metaprogramming
class ActiveRecord
  @@attributes = {}

  def self.attribute(name, type = :string)
    @@attributes[name] = type

    define_method(name) do
      @attributes[name]
    end

    define_method("#{name}=") do |value|
      @attributes[name] = cast_type(value, type)
    end
  end

  def self.attributes
    @@attributes
  end

  def initialize
    @attributes = {}
  end

  private

  def cast_type(value, type)
    case type
    when :string
      value.to_s
    when :integer
      value.to_i
    when :float
      value.to_f
    when :boolean
      !!value
    else
      value
    end
  end
end

class User < ActiveRecord
  attribute :name, :string
  attribute :age, :integer
  attribute :email, :string
  attribute :active, :boolean
end

user = User.new
user.name = "Alice"
user.age = 25
user.email = "[email protected]"
user.active = true

puts "Name: #{user.name}, Age: #{user.age}, Active: #{user.active}"

# 4. Module metaprogramming
class MacroModule
  def self.delegated_methods(*methods, to:)
    methods.each do |method|
      define_method(method) do |*args, &block|
        send(to).send(method, *args, &block)
      end
    end
  end
end

class Person
  MacroModule.delegated_methods :name, :email, to: :@contact_info

  def initialize
    @contact_info = OpenStruct.new
  end
end

require 'ostruct'

person = Person.new
person.name = "Bob"
person.email = "[email protected]"

puts person.name
puts person.email

# 5. Singleton methods and eigenclass
obj = Object.new

# Define singleton method
def obj.special_method
  "This is a singleton method!"
end

puts obj.special_method

# Define singleton methods using eigenclass
class << obj
  def another_special_method
    "Another singleton method!"
  end
end

puts obj.another_special_method

# 6. Class methods as singleton methods
class MyClass
  # This creates a singleton method on the class object
  def self.class_method
    "This is a class method"
  end

  # Using eigenclass for class methods
  class << self
    def another_class_method
      "Another class method"
    end
  end
end

puts MyClass.class_method
puts MyClass.another_class_method

# 7. Dynamic class creation
dynamic_class = Class.new do
  def initialize(name)
    @name = name
  end

  def greet
    "Hello, #{@name}!"
  end
end

instance = dynamic_class.new("Dynamic Class")
puts instance.greet

# 8. Method introspection
class IntrospectionExample
  def public_method; end
  protected :def protected_method; end
  private :def private_method; end

  def self.class_method; end
end

obj = IntrospectionExample.new

puts "Public methods: #{obj.public_methods(false).sort}"
puts "Protected methods: #{obj.protected_methods(false).sort}"
puts "Private methods: #{obj.private_methods(false).sort}"
puts "Class methods: #{IntrospectionExample.methods(false).sort}"

# Method information
if obj.respond_to?(:public_method)
  puts "Object responds to :public_method"
  puts "Method arity: #{obj.method(:public_method).arity}"
end

# 9. Using const_missing for dynamic constants
module DynamicConstants
  def self.const_missing(name)
    if name.to_s.start_with?('CONFIG_')
      # Load configuration dynamically
      config_key = name.to_s.sub('CONFIG_', '').downcase
      "Configuration for #{config_key}"
    else
      super
    end
  end
end

puts DynamicConstants::CONFIG_DATABASE
puts DynamicConstants::CONFIG_API

# 10. Advanced metaprogramming with modules
class AdvancedMetaprogramming
  def self.add_validator(attr_name, validator_proc)
    define_method("#{attr_name}_valid?") do
      value = instance_variable_get("@#{attr_name}")
      validator_proc.call(value)
    end
  end

  def self.attr_accessor_with_validation(attr_name, validator_proc)
    attr_writer attr_name

    define_method(attr_name) do
      instance_variable_get("@#{attr_name}")
    end

    add_validator(attr_name, validator_proc)
  end
end

class ValidatedUser
  extend AdvancedMetaprogramming

  attr_accessor_with_validation :email, ->(value) { value.match?(/A[^@s]+@[^@s]+z/) }
  attr_accessor_with_validation :age, ->(value) { value.is_a?(Integer) && value > 0 }

  def initialize
    @validations = {}
  end

  def valid?
    email_valid? && age_valid?
  end
end

user = ValidatedUser.new
user.email = "[email protected]"
user.age = 25

puts "User valid: #{user.valid?}"

# 11. Method chaining with self
class MethodChaining
  def initialize
    @operations = []
  end

  def add(value)
    @operations << [:add, value]
    self
  end

  def multiply(value)
    @operations << [:multiply, value]
    self
  end

  def result
    @operations.reduce(0) do |acc, (op, value)|
      case op
      when :add then acc + value
      when :multiply then acc * value
      end
    end
  end
end

result = MethodChaining.new.add(5).multiply(2).add(3).result
puts "Method chaining result: #{result}"

# 12. Using define_method with blocks
class DynamicBlockMethods
  def self.create_math_operation(name, operation)
    define_method(name) do |*args|
      args.reduce(&operation)
    end
  end
end

DynamicBlockMethods.create_math_operation(:sum, :+)
DynamicBlockMethods.create_math_operation(:product, :*)

math_ops = DynamicBlockMethods.new
puts "Sum of 1, 2, 3, 4: #{math_ops.sum(1, 2, 3, 4)}"
puts "Product of 2, 3, 4: #{math_ops.product(2, 3, 4)}"

# 13. Instance_eval and class_eval
class EvalExample
  def initialize
    @value = 10
  end

  def demonstrate_instance_eval
    instance_eval do
      puts "Inside instance_eval, @value = #{@value}"
      @value = 20
    end
    puts "After instance_eval, @value = #{@value}"
  end
end

class << EvalExample
  def demonstrate_class_eval
    class_eval do
      def class_level_method
        "I was added with class_eval"
      end
    end
  end
end

EvalExample.demonstrate_class_eval

obj = EvalExample.new
obj.demonstrate_instance_eval
puts obj.class_level_method

# 14. Method tracing with alias_method
class MethodTracer
  def self.trace_methods(*method_names)
    method_names.each do |method_name|
      original_method = instance_method(method_name)

      define_method(method_name) do |*args, &block|
        puts "Calling #{method_name} with args: #{args}"
        result = original_method.bind(self).call(*args, &block)
        puts "#{method_name} returned: #{result}"
        result
      end
    end
  end

  def add(a, b)
    a + b
  end

  def multiply(a, b)
    a * b
  end
end

MethodTracer.trace_methods(:add, :multiply)

tracer = MethodTracer.new
puts tracer.add(5, 3)
puts tracer.multiply(4, 6)