Module: WifiWand::ModelSubclassContract

Defined in:
lib/wifi_wand/models/model_subclass_contract.rb

Overview

Validates that subclasses of BaseModel implement every required method with the correct visibility. This module references BaseModel by name and must be loaded after base_model.rb is required.

Constant Summary collapse

REQUIRED_SUBCLASS_METHODS =
{
  _available_network_names:    :any_visibility,
  _connected_network_name:     :any_visibility,
  _connect:                    :any_visibility,
  _disconnect:                 :any_visibility,
  _ipv4_addresses:             :any_visibility,
  _ipv6_addresses:             :any_visibility,
  _preferred_network_password: :any_visibility,
  bssid:                       :public,
  connected?:                  :public,
  connection_security_type:    :public,
  default_interface:           :public,
  is_wifi_interface?:          :public,
  mac_address:                 :public,
  nameservers:                 :public,
  network_hidden?:             :public,
  open_resource:               :public,
  probe_wifi_interface:        :public,
  preferred_networks:          :public,
  remove_preferred_network:    :public,
  set_nameservers:             :public,
  signal_quality:              :public,
  validate_os_preconditions:   :public,
  wifi_off:                    :public,
  wifi_on:                     :public,
  wifi_on?:                    :public,
}.freeze

Class Method Summary collapse

Class Method Details

.subclass_implements_required_method?(subclass, method_name, required_visibility) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
56
57
58
59
60
61
62
# File 'lib/wifi_wand/models/model_subclass_contract.rb', line 53

def self.subclass_implements_required_method?(subclass, method_name, required_visibility)
  case required_visibility
  when :public
    subclass_publicly_overrides_method?(subclass, method_name)
  when :any_visibility
    subclass_overrides_method?(subclass, method_name)
  else
    raise ArgumentError, "Unknown required method visibility: #{required_visibility.inspect}"
  end
end

.subclass_overrides_method?(subclass, method_name) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
40
41
42
43
# File 'lib/wifi_wand/models/model_subclass_contract.rb', line 37

def self.subclass_overrides_method?(subclass, method_name)
  method = if subclass.method_defined?(method_name) || subclass.private_method_defined?(method_name)
    subclass.instance_method(method_name)
  end

  method && method.owner != BaseModel
end

.subclass_publicly_overrides_method?(subclass, method_name) ⇒ Boolean

Returns:

  • (Boolean)


45
46
47
48
49
50
51
# File 'lib/wifi_wand/models/model_subclass_contract.rb', line 45

def self.subclass_publicly_overrides_method?(subclass, method_name)
  method = if subclass.public_method_defined?(method_name)
    subclass.public_instance_method(method_name)
  end

  method && method.owner != BaseModel
end

.validate_subclass!(subclass) ⇒ Object



75
76
77
78
79
80
81
82
83
# File 'lib/wifi_wand/models/model_subclass_contract.rb', line 75

def self.validate_subclass!(subclass)
  trace = TracePoint.new(:end) do |tp|
    if tp.self == subclass
      verify_required_methods_implemented(subclass)
      trace.disable
    end
  end
  trace.enable
end

.verify_required_methods_implemented(subclass) ⇒ Object



64
65
66
67
68
69
70
71
72
73
# File 'lib/wifi_wand/models/model_subclass_contract.rb', line 64

def self.verify_required_methods_implemented(subclass)
  missing_methods = REQUIRED_SUBCLASS_METHODS.reject do |method_name, required_visibility|
    subclass_implements_required_method?(subclass, method_name, required_visibility)
  end.keys

  unless missing_methods.empty?
    subclass_name = subclass.name || '(anonymous)'
    raise NotImplementedError, "Subclass #{subclass_name} must implement #{missing_methods.inspect}"
  end
end