Class: Kielce::KielceData

Inherits:
BasicObject
Defined in:
lib/kielce/kielce_data.rb

Overview

By extending BasicObject instead of Object, we don’t have to worry about user data conflicting with method names in Object or Kernel

the data.

(The strange “xx_kielce_” naming is to avoid conflicts with user-chosen names)

Constant Summary collapse

@@error_output =
$stderr

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, root = nil, obj_name = nil) ⇒ KielceData

Returns a new instance of KielceData.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/kielce/kielce_data.rb', line 66

def initialize(data, root = nil, obj_name = nil)
  
  INVALID_KEYS.each do |key|
    ::Kernel.send(:raise, InvalidKeyError.new("Invalid Key: #{key} may not be used as a key.", key)) if data.has_key?(key)
  end

  @xx_kielce_obj_name = obj_name.nil? ? "" : obj_name

  @xx_kielce_data = data

  # Remember, root may be a BasicObject and, therefore, not define .nil
  @xx_kielce_root = (root == nil) ? self : root

  @xx_kielce_data.each do |key, value|
    if value.is_a?(::Hash)
      @xx_kielce_data[key] = ::Kielce::KielceData.new(value, @xx_kielce_root, "#{@xx_kielce_obj_name}#{key}.")
    end
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, **keyword_args, &block) ⇒ Object

Provides the “magic” that allows users to access data using method syntax. This method is called whenever a method that doesn’t exist is invoked. It then looks through the hash for a key with the same name as the method.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/kielce/kielce_data.rb', line 101

def method_missing(name, *args, **keyword_args, &block)

  # $stderr.puts "Processing #{name} in #{@xx_kielce_obj_name}"

  # Convert the name to a symbol. (It is probably already a symbol, but the extra .to_sym won't hurt)
  # Then complian if there isn't a data object by that name.
  name_sym = name.to_sym
  full_name = "#{@xx_kielce_obj_name}#{name}"
  unless @xx_kielce_data.has_key?(name_sym)
    # The first ("message") parameter is currently unused.  The message can be changed, if desired.
    ::Kernel.send(:raise, NoKeyError.new("Unrecognized Key: #{full_name}", full_name))
  end

  # Get the requested data object.
  # If the object is a lambda, execute the lambda.
  # Otherwise, just return it.
  item = @xx_kielce_data[name_sym]
  if item.is_a?(::Proc)
    if item.parameters.any? { |i| i.last == :root }
      @@error_output.puts 'WARNING! Lambda parameter named root shadows instance method root.'
    end

    #$stderr.puts item.parameters.inspect
    keyword_params = item.parameters.select { |i| i.first == :keyreq || i.first == :key }
    num_keyword = keyword_params.size
    num_args = item.parameters.size - num_keyword

    #$stderr.puts "-----------"
    #$stderr.puts args.inspect
    #$stderr.puts keyword_args.inspect
    #$stderr.puts "Num each: #{num_args} #{num_keyword}"

    if num_args == 0 && num_keyword == 0
      return instance_exec(&item)
    elsif num_args > 0 && num_keyword == 0
      return instance_exec(*args, &item)
    elsif num_keyword > 0
      return instance_exec(*args, **keyword_args, &item)
    else
      $stderr.puts "FAIL.  Shouldn't get here!"
    end
  end

  if args.length != 0 || keyword_args.size != 0
    @@error_output.puts "WARNING! #{full_name} is not a function and doesn't expect parameters."
  end

  @xx_kielce_data[name_sym]
end

Class Method Details

.error_outputObject



58
59
60
# File 'lib/kielce/kielce_data.rb', line 58

def self.error_output
  @@error_output
end

.error_output=(val) ⇒ Object



62
63
64
# File 'lib/kielce/kielce_data.rb', line 62

def self.error_output=(val)
  @@error_output=val
end

Instance Method Details

#inspectObject



90
91
92
# File 'lib/kielce/kielce_data.rb', line 90

def inspect
  "KielceData: #{@xx_kielce_obj_name} #{@xx_kielce_data.inspect}"
end

#is_a?(klass) ⇒ Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/kielce/kielce_data.rb', line 94

def is_a?(klass)
  klass == ::Kielce::KielceData
end

#rootObject



86
87
88
# File 'lib/kielce/kielce_data.rb', line 86

def root
  @xx_kielce_root
end