Skip to content

Instantly share code, notes, and snippets.

@shikhalev
Created November 18, 2014 10:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shikhalev/5f19659a7ed82ce83c58 to your computer and use it in GitHub Desktop.
Save shikhalev/5f19659a7ed82ce83c58 to your computer and use it in GitHub Desktop.
Для статьи «Метапрограммирование в Ruby: разбор примера»
# encoding: utf-8
require './prop00'
class Alpha
property :alpha, :beta
attr_accessor :gamma
end
a = Alpha.new
a.alpha = 1
a.beta = 2
a.gamma = 3
p [a.alpha, a.beta, a.gamma]
p a
# encoding: utf-8
require './prop01'
class Alpha
property :alpha, default: 100
property :beta, default_proc: proc { |o| o.class.name }
property :gamma, default_proc: :class
end
a = Alpha.new
p [a.alpha, a.beta, a.gamma]
p a
# encoding: utf-8
require './prop02'
class Alpha
property :alpha
property :beta do |obj, prop, value|
p [obj, prop, value]
end
end
a = Alpha.new
a.alpha = 100
a.beta = 200
# encoding: utf-8
require './prop03'
class Alpha
property :alpha, filter: Integer
property :beta, filter: proc { |x| Integer === x && x > 0 },
on_invalid: StandardError
end
a = Alpha.new
a.alpha = 11
a.beta = 2
p a
a.alpha = "String"
p a
a.beta = -1
p a
# encoding: utf-8
class Module
private
def prop name
varnm = "@#{name}"
getnm = name
setnm = "#{name}="
define_method getnm do
instance_variable_get varnm
end
define_method setnm do |value|
instance_variable_set varnm, value
end
end
def property *names
names.each do |nm|
prop nm
end
end
end
# encoding: utf-8
class Module
private
def prop name, default: nil, default_proc: nil
varnm = "@#{name}"
getnm = name
setnm = "#{name}="
define_method getnm do
if ! instance_variable_defined?(varnm)
if default_proc
instance_variable_set varnm,
default_proc.to_proc.call(self)
else
instance_variable_set varnm, default
end
end
instance_variable_get varnm
end
define_method setnm do |value|
instance_variable_set varnm, value
end
end
def property *names, default: nil, default_proc: nil
names.each do |nm|
prop nm, default: default, default_proc: default_proc
end
end
end
# encoding: utf-8
class Module
private
def prop name, default: nil, default_proc: nil, &block
varnm = "@#{name}"
getnm = name
setnm = "#{name}="
define_method getnm do
if ! instance_variable_defined?(varnm)
if default_proc
instance_variable_set varnm,
default_proc.to_proc.call(self)
else
instance_variable_set varnm, default
end
end
instance_variable_get varnm
end
define_method setnm do |value|
instance_variable_set varnm, value
if block
block.call self, name, value
end
end
end
def property *names, default: nil, default_proc: nil, &block
names.each do |nm|
prop nm, default: default, default_proc: default_proc, &block
end
end
end
# encoding: utf-8
class Module
private
def prop name, default: nil, default_proc: nil, filter: nil, on_invalid: nil,
&block
varnm = "@#{name}"
getnm = name
setnm = "#{name}="
if !(on_invalid == nil ||
(Class === on_invalid && on_invalid <= Exception) || Proc === on_invalid)
raise TypeError,
"Invalid type of 'on_invalid' argument: #{on_invalid.class}", caller
end
define_method getnm do
if ! instance_variable_defined?(varnm)
if default_proc
instance_variable_set varnm,
default_proc.to_proc.call(self)
else
instance_variable_set varnm, default
end
end
instance_variable_get varnm
end
define_method setnm do |value|
if filter && !(filter === value)
if Class === on_invalid && on_invalid <= Exception
raise on_invalid,
"Invalid property (#{name}) value: #{value.inspect}!", caller
elsif Proc === on_invalid
on_invalid.call self, name, value
end
else
instance_variable_set varnm, value
if block
block.call self, name, value
end
end
end
end
def property *names, default: nil, default_proc: nil, filter: nil,
on_invalid: nil, &block
names.each do |nm|
prop nm, default: default, default_proc: default_proc, filter: filter,
on_invalid: on_invalid, &block
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment