File: abstract_type.rb

package info (click to toggle)
ruby-abstract-type 0.0.7-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 172 kB
  • sloc: ruby: 205; makefile: 4
file content (119 lines) | stat: -rw-r--r-- 2,679 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# encoding: utf-8

# Module to allow class and methods to be abstract
module AbstractType

  # Hook called when module is included
  #
  # @param [Module] descendant
  #   the module or class including AbstractType
  #
  # @return [undefined]
  #
  # @api private
  def self.included(descendant)
    super
    create_new_method(descendant)
    descendant.extend(AbstractMethodDeclarations)
  end

  private_class_method :included

  # Define the new method on the abstract type
  #
  # Ensures that the instance cannot be of the abstract type
  # and must be a descendant.
  #
  # @param [Class] abstract_class
  #
  # @return [undefined]
  #
  # @api private
  def self.create_new_method(abstract_class)
    abstract_class.define_singleton_method(:new) do |*args, &block|
      if equal?(abstract_class)
        fail NotImplementedError, "#{inspect} is an abstract type"
      else
        super(*args, &block)
      end
    end
  end

  private_class_method :create_new_method

  module AbstractMethodDeclarations

    # Create abstract instance methods
    #
    # @example
    #   class Foo
    #     include AbstractType
    #
    #     # Create an abstract instance method
    #     abstract_method :some_method
    #   end
    #
    # @param [Array<#to_s>] names
    #
    # @return [self]
    #
    # @api public
    def abstract_method(*names)
      names.each(&method(:create_abstract_instance_method))
      self
    end

    # Create abstract singleton methods
    #
    # @example
    #   class Foo
    #     include AbstractType
    #
    #     # Create an abstract instance method
    #     abstract_singleton_method :some_method
    #   end
    #
    # @param [Array<#to_s>] names
    #
    # @return [self]
    #
    # @api private
    def abstract_singleton_method(*names)
      names.each(&method(:create_abstract_singleton_method))
      self
    end

  private

    # Create abstract singleton method
    #
    # @param [#to_s] name
    #   the name of the method to create
    #
    # @return [undefined]
    #
    # @api private
    def create_abstract_singleton_method(name)
      define_singleton_method(name) do |*|
        fail NotImplementedError, "#{inspect}.#{name} is not implemented"
      end
    end

    # Create abstract instance method
    #
    # @param [#to_s] name
    #   the name of the method to create
    #
    # @return [undefined]
    #
    # @api private
    def create_abstract_instance_method(name)
      define_method(name) do |*|
        fail NotImplementedError, "#{self.class}##{name} is not implemented"
      end
    end

  end # module AbstractMethodDeclarations
end # module AbstractType

require 'abstract_type/version'