Class: Checkr::APIClass
- Inherits:
-
Object
- Object
- Checkr::APIClass
- Defined in:
- lib/checkr/api_class.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#json ⇒ Object
Returns the value of attribute json.
Class Method Summary collapse
- .api_class_method(name, method, path = nil, opts = {}) ⇒ Object
- .api_instance_method(name, method, path = nil, opts = {}) ⇒ Object
- .api_lambda(out_name, out_method, out_path = nil, out_opts = {}) ⇒ Object
- .api_lambda_construct(resp, constructor, this) ⇒ Object
- .attribute(name, klass = nil, opts = {}) ⇒ Object
- .attribute_aliases ⇒ Object
- .attribute_get_lambda(name, opts = {}) ⇒ Object
- .attribute_names ⇒ Object
-
.attribute_set_lambda(name, klass = nil, opts = {}) ⇒ Object
TODO(joncalhoun): Add tests for this.
- .attribute_writer_alias(name, attr_name) ⇒ Object
- .attribute_writer_names ⇒ Object
- .changed_lambda ⇒ Object
- .compose_api_path(path, arguments, params = {}, this = self) ⇒ Object
- .compose_arguments(method, arg_names, *args) ⇒ Object
-
.compose_params(params = {}, unused_args = {}, default_params = {}, this = self) ⇒ Object
Priority: params > unused_args > default_params.
- .construct(json = {}) ⇒ Object
-
.determine_attr_value(klass, val, opts = {}, this = self) ⇒ Object
TODO(joncalhoun): Maybe make this delay calling nested constructors until the main obj is fully constructed otherwise..
- .determine_unused_args(path, arg_names, arguments, this = self) ⇒ Object
- .path ⇒ Object
- .register_subclass(subclass, name = nil) ⇒ Object
- .subclass_fetch(name) ⇒ Object
- .subclasses ⇒ Object
- .validate_args(arg_names, *args) ⇒ Object
Instance Method Summary collapse
- #attributes ⇒ Object
- #changed_attribute_names ⇒ Object
- #changed_attributes ⇒ Object
- #clear_changed_attributes ⇒ Object
-
#construct(json = {}) ⇒ Object
Alias, but dont declare it as one because we need to use overloaded methods.
-
#initialize(id = nil) ⇒ APIClass
constructor
A new instance of APIClass.
- #inspect ⇒ Object
- #mark_attribute_changed(attr_name) ⇒ Object
- #non_nil_attributes ⇒ Object
- #path ⇒ Object
- #refresh_from(json = {}) ⇒ Object
- #to_json(*a) ⇒ Object
- #to_s(*args) ⇒ Object
Constructor Details
#initialize(id = nil) ⇒ APIClass
Returns a new instance of APIClass.
109 110 111 |
# File 'lib/checkr/api_class.rb', line 109 def initialize(id=nil) refresh_from(id) end |
Instance Attribute Details
#json ⇒ Object
Returns the value of attribute json.
3 4 5 |
# File 'lib/checkr/api_class.rb', line 3 def json @json end |
Class Method Details
.api_class_method(name, method, path = nil, opts = {}) ⇒ Object
13 14 15 16 |
# File 'lib/checkr/api_class.rb', line 13 def self.api_class_method(name, method, path=nil, opts={}) singleton = class << self; self end singleton.send(:define_method, name, api_lambda(name, method, path, opts)) end |
.api_instance_method(name, method, path = nil, opts = {}) ⇒ Object
18 19 20 |
# File 'lib/checkr/api_class.rb', line 18 def self.api_instance_method(name, method, path=nil, opts={}) self.send(:define_method, name, api_lambda(name, method, path, opts)) end |
.api_lambda(out_name, out_method, out_path = nil, out_opts = {}) ⇒ Object
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/checkr/api_class.rb', line 224 def self.api_lambda(out_name, out_method, out_path=nil, out_opts={}) # Path, Opts, and Klass are all optional, so we have to determine # which were provided using the criteria: temp = [out_path, out_opts] out_path = temp.select{ |t| t.is_a?(String) }.first || nil out_opts = temp.select{ |t| t.is_a?(Hash) }.first || {} out_arg_names = out_opts[:arguments] || [] out_constructor = out_opts[:constructor] || :self out_default_params = out_opts[:default_params] || {} lambda do |*args| # Make sure we have clean data constructor = out_constructor method = out_method path = nil path = out_path.dup if out_path arg_names = nil arg_names = out_arg_names.dup if out_arg_names default_params = out_default_params # dont need to dup this since it isn't modified directly validate_args(arg_names, *args) arguments = compose_arguments(method, arg_names, *args) composed_path = compose_api_path(path, arguments, arguments[:params]) unused_args = determine_unused_args(path, arg_names, arguments) arguments[:params] = compose_params(arguments[:params], unused_args, default_params) resp = Checkr.request(method, composed_path, arguments[:params], arguments[:opts]) api_lambda_construct(resp, constructor, self) end end |
.api_lambda_construct(resp, constructor, this) ⇒ Object
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/checkr/api_class.rb', line 257 def self.api_lambda_construct(resp, constructor, this) case constructor when Class constructor.construct(resp) when Proc constructor.call(resp) when Symbol if constructor == :self this.construct(resp) else klass = Util.constantize(constructor) if klass klass.construct(resp) else raise ArgumentError.new("Invalid constructor. See method definition.") end end else this.construct(resp) end end |
.attribute(name, klass = nil, opts = {}) ⇒ Object
22 23 24 25 26 27 28 |
# File 'lib/checkr/api_class.rb', line 22 def self.attribute(name, klass=nil, opts={}) @attribute_names ||= Set.new @attribute_names << name.to_sym self.send(:define_method, "#{name}", attribute_get_lambda(name, opts)) self.send(:define_method, "#{name}=", attribute_set_lambda(name, klass, opts)) end |
.attribute_aliases ⇒ Object
59 60 61 62 63 64 65 66 |
# File 'lib/checkr/api_class.rb', line 59 def self.attribute_aliases @attribute_aliases ||= Set.new unless self == APIClass @attribute_aliases + self.superclass.attribute_aliases else @attribute_aliases end end |
.attribute_get_lambda(name, opts = {}) ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/checkr/api_class.rb', line 182 def self.attribute_get_lambda(name, opts={}) lambda do if !instance_variables_include?(name) if opts[:default] self.send("#{name}=", opts[:default]) instance_variable_get("@#{name}") else nil end else instance_variable_get("@#{name}") end end end |
.attribute_names ⇒ Object
50 51 52 53 54 55 56 57 |
# File 'lib/checkr/api_class.rb', line 50 def self.attribute_names @attribute_names ||= Set.new unless self == APIClass @attribute_names + self.superclass.attribute_names else @attribute_names end end |
.attribute_set_lambda(name, klass = nil, opts = {}) ⇒ Object
TODO(joncalhoun): Add tests for this
198 199 200 201 202 203 204 205 206 |
# File 'lib/checkr/api_class.rb', line 198 def self.attribute_set_lambda(name, klass=nil, opts={}) lambda do |val| if klass val = determine_attr_value(klass, val, opts) end instance_variable_set("@#{name}", val) mark_attribute_changed(name) end end |
.attribute_writer_alias(name, attr_name) ⇒ Object
30 31 32 33 34 35 36 |
# File 'lib/checkr/api_class.rb', line 30 def self.attribute_writer_alias(name, attr_name) @attribute_aliases ||= Set.new @attribute_aliases << name.to_sym # self.send(:alias_method, name, attr_name) self.send(:alias_method, "#{name}=", "#{attr_name}=") end |
.attribute_writer_names ⇒ Object
68 69 70 |
# File 'lib/checkr/api_class.rb', line 68 def self.attribute_writer_names self.attribute_names + self.attribute_aliases end |
.changed_lambda ⇒ Object
101 102 103 104 105 106 107 |
# File 'lib/checkr/api_class.rb', line 101 def self.changed_lambda # This runs in the context of an instance since it is used in # an api_instance_method lambda do |instance| instance.changed_attributes end end |
.compose_api_path(path, arguments, params = {}, this = self) ⇒ Object
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/checkr/api_class.rb', line 342 def self.compose_api_path(path, arguments, params={}, this=self) # Setup the path using the following attribute order: # 1. Args passed in # 2. Args on this # 3. Args on this.class ret = (path || this.path || "").dup if ret.include?(":") missing = Set.new matches = ret.scan(/:([^\/]*)/).flatten.map(&:to_sym) matches.each do |match| value = arguments[match] value ||= params[match] || params[match.to_s] begin value ||= this.send(match) rescue NoMethodError end begin value ||= this.class.send(match) unless this.class == Class rescue NoMethodError end if value.nil? missing << match end ret.sub!(match.inspect, "#{value}") end unless missing.empty? raise InvalidRequestError.new("Could not determine the full URL to request. Missing the following values: #{missing.to_a.join(', ')}.", "url") end end ret end |
.compose_arguments(method, arg_names, *args) ⇒ Object
326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/checkr/api_class.rb', line 326 def self.compose_arguments(method, arg_names, *args) arguments = {} names = arg_names.dup + [:params, :opts] names.each_with_index do |k, i| arguments[k] = args[i] if args.length > i end arguments[:params] ||= {} arguments[:opts] ||= {} arguments end |
.compose_params(params = {}, unused_args = {}, default_params = {}, this = self) ⇒ Object
Priority: params > unused_args > default_params
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/checkr/api_class.rb', line 307 def self.compose_params(params={}, unused_args={}, default_params={}, this=self) ret = {} # Handle the default params if default_params.is_a?(Proc) default_params = default_params.call(this) elsif default_params.is_a?(Symbol) default_params = this.send(default_params) end ret.update(default_params || {}) ret.update(unused_args || {}) ret.update(params || {}) ret end |
.construct(json = {}) ⇒ Object
113 114 115 |
# File 'lib/checkr/api_class.rb', line 113 def self.construct(json={}) self.new.refresh_from(json) end |
.determine_attr_value(klass, val, opts = {}, this = self) ⇒ Object
TODO(joncalhoun): Maybe make this delay calling nested constructors until the main obj is fully constructed otherwise.. for now code around it by references to parent in nested objects.
209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/checkr/api_class.rb', line 209 def self.determine_attr_value(klass, val, opts={}, this=self) args = (opts && opts[:nested]) ? [val, this] : [val] if klass.is_a?(Proc) klass.call(*args) elsif klass.is_a?(Class) klass.construct(*args) else klass = Util.constantize(klass) klass.construct(*args) end end |
.determine_unused_args(path, arg_names, arguments, this = self) ⇒ Object
380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
# File 'lib/checkr/api_class.rb', line 380 def self.determine_unused_args(path, arg_names, arguments, this=self) unused = Set.new(arg_names) path ||= this.path raise ArgumentError.new("Path has never been set") unless path if path.include?(":") matches = path.scan(/:([^\/]*)/).flatten.map(&:to_sym) matches.each{ |m| unused.delete(m) } end ret = {} unused.each do |arg_name| ret[arg_name] = arguments[arg_name] end ret end |
.path ⇒ Object
5 6 7 |
# File 'lib/checkr/api_class.rb', line 5 def self.path raise NotImplementedError.new("APIClass is an abstract class. Please refer to its subclasses: #{subclasses}") end |
.register_subclass(subclass, name = nil) ⇒ Object
148 149 150 151 152 153 154 155 156 |
# File 'lib/checkr/api_class.rb', line 148 def self.register_subclass(subclass, name=nil) @subclasses ||= Set.new @subclasses << subclass unless name.nil? @subclasses_hash ||= {} @subclasses_hash[name] = subclass end end |
.subclass_fetch(name) ⇒ Object
141 142 143 144 145 146 |
# File 'lib/checkr/api_class.rb', line 141 def self.subclass_fetch(name) @subclasses_hash ||= {} if @subclasses_hash.has_key?(name) @subclasses_hash[name] end end |
.subclasses ⇒ Object
137 138 139 |
# File 'lib/checkr/api_class.rb', line 137 def self.subclasses return @subclasses ||= Set.new end |
.validate_args(arg_names, *args) ⇒ Object
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/checkr/api_class.rb', line 282 def self.validate_args(arg_names, *args) # Make sure we have valid arguments if args.length > arg_names.length if args.length > arg_names.length + 2 # more than params and opts were included raise ArgumentError.new("Too many arguments") else # Params and opts are allowed, but they must be hashes args[arg_names.length..-1].each do |arg| unless arg.is_a?(Hash) || arg.nil? raise ArgumentError.new("Invalid Param or Opts argument") end end end end if args.length < arg_names.length missing = arg_names[args.length..-1] raise ArgumentError.new("Missing arguments #{missing}") end end |
Instance Method Details
#attributes ⇒ Object
38 39 40 41 42 43 44 |
# File 'lib/checkr/api_class.rb', line 38 def attributes attributes = {} self.class.attribute_names.each do |attr| attributes[attr.to_sym] = self.send(attr) end attributes end |
#changed_attribute_names ⇒ Object
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/checkr/api_class.rb', line 77 def changed_attribute_names @changed_attribute_names ||= Set.new attributes.each do |key, val| next if @changed_attribute_names.include?(key) if val.is_a?(Array) || val.is_a?(Hash) @changed_attribute_names << key if json[key] != val end end @changed_attribute_names end |
#changed_attributes ⇒ Object
88 89 90 91 92 93 94 |
# File 'lib/checkr/api_class.rb', line 88 def changed_attributes ret = {} changed_attribute_names.each do |attr| ret[attr] = send(attr) end ret end |
#clear_changed_attributes ⇒ Object
96 97 98 |
# File 'lib/checkr/api_class.rb', line 96 def clear_changed_attributes @changed_attribute_names = Set.new end |
#construct(json = {}) ⇒ Object
Alias, but dont declare it as one because we need to use overloaded methods.
133 134 135 |
# File 'lib/checkr/api_class.rb', line 133 def construct(json={}) refresh_from(json) end |
#inspect ⇒ Object
158 159 160 161 |
# File 'lib/checkr/api_class.rb', line 158 def inspect id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : "" "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(attributes) end |
#mark_attribute_changed(attr_name) ⇒ Object
72 73 74 75 |
# File 'lib/checkr/api_class.rb', line 72 def mark_attribute_changed(attr_name) @changed_attribute_names ||= Set.new @changed_attribute_names << attr_name.to_sym end |
#non_nil_attributes ⇒ Object
46 47 48 |
# File 'lib/checkr/api_class.rb', line 46 def non_nil_attributes attributes.select{|k, v| !v.nil? } end |
#path ⇒ Object
9 10 11 |
# File 'lib/checkr/api_class.rb', line 9 def path raise NotImplementedError.new("APIClass is an abstract class. Please refer to its subclasses: #{APIClass.subclasses}") end |
#refresh_from(json = {}) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/checkr/api_class.rb', line 117 def refresh_from(json={}) unless json.is_a?(Hash) json = { :id => json } end self.json = Util.sorta_deep_clone(json) json.each do |k, v| if self.class.attribute_writer_names.include?(k.to_sym) self.send("#{k}=", v) end end clear_changed_attributes self end |
#to_json(*a) ⇒ Object
167 168 169 |
# File 'lib/checkr/api_class.rb', line 167 def to_json(*a) JSON.generate(non_nil_attributes) end |
#to_s(*args) ⇒ Object
163 164 165 |
# File 'lib/checkr/api_class.rb', line 163 def to_s(*args) JSON.pretty_generate(non_nil_attributes) end |