lib/r_range/ruby.ex

defmodule RRange.Ruby do
  @moduledoc """
  Summarized all of Ruby's Range functions.
  Functions corresponding to the following patterns are not implemented
   - When a function with the same name already exists in Elixir.
   - When a method name includes `!`.
   - %, ==, ===
  """
  @spec __using__(any) :: list
  defmacro __using__(_opts) do
    RUtils.define_all_functions!(__MODULE__)
  end

  use RRange.RubyEnd

  # https://ruby-doc.org/core-3.1.0/Range.html
  # [:begin, :bsearch, :count, :cover?, :each, :end, :entries, :eql?, :exclude_end?, :first, :hash, :include?, :inspect, :last, :max, :member?, :min, :minmax, :size, :step, :to_a, :to_s]
  # |> RUtils.required_functions([Range, REnum])
  # ✔ begin
  # × bsearch
  # ✔ cover?
  # ✔ end
  # ✔ eql?
  # × exclude_end?
  # × hash
  # ✔ inspect
  # ✔ last
  # ✔ step
  # ✔ to_s

  @doc """
  Returns true if list1 == list2.
  ## Examples
      iex> 1..3
      iex> |> RList.eql?(1..3)
      true

      iex> 1..3
      iex> |> RList.eql?(1..4)
      false
  """
  @spec eql?(Range.t(), Range.t()) :: boolean()
  def eql?(range1, range2) do
    range1 == range2
  end

  @doc """
  Returns the first element of range.
  ## Examples
      iex> RList.begin(1..3)
      1
  """
  @spec begin(Range.t()) :: integer()
  def begin(begin.._) do
    begin
  end

  if(VersionManager.support_version?()) do
    @doc """
    Returns Stream that from given range split into by given step.
    ## Examples
        iex> RList.step(1..10, 2)
        iex> |> Enum.to_list()
        [1, 3, 5, 7, 9]
    """
    @spec step(Range.t(), integer()) :: Enum.t()
    def step(begin..last, step) do
      begin..last//step
      |> REnum.Ruby.lazy()
    end

    @doc """
    Executes `Enum.each` to g given range split into by given step.
    ## Examples
        iex> RList.step(1..10, 2, &IO.inspect(&1))
        iex> |> Enum.to_list()
        # 1
        # 3
        # 5
        # 7
        # 9
        :ok
    """
    @spec step(Range.t(), integer(), function()) :: :ok
    def step(begin..last, step, func) do
      begin..last//step
      |> Enum.each(func)
    end
  end

  defdelegate inspect(range), to: Kernel, as: :inspect
  defdelegate to_s(range), to: Kernel, as: :inspect
  defdelegate cover?(range, n), to: Enum, as: :member?
end