core 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +11 -0
- data/Rakefile +20 -0
- data/lib/core.rb +12 -0
- data/lib/core/accessor.rb +114 -0
- data/lib/core/forwardable.rb +85 -0
- data/lib/core/functor.rb +19 -0
- data/lib/core/hash.rb +13 -0
- data/lib/core/inspect.rb +20 -0
- data/lib/core/module.rb +93 -0
- data/lib/core/object.rb +64 -0
- data/lib/core/this.rb +78 -0
- data/lib/kinda-core.rb +1 -0
- data/test/__all__.rb +5 -0
- data/test/accessor_test.rb +131 -0
- data/test/forwardable_test.rb +51 -0
- data/test/module_test.rb +84 -0
- data/test/object_test.rb +28 -0
- data/test/this_test.rb +11 -0
- metadata +71 -0
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "rake/testtask"
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "hanna/rdoctask"
|
5
|
+
rescue LoadError
|
6
|
+
require "rake/rdoctask"
|
7
|
+
end
|
8
|
+
|
9
|
+
task :default => [:test]
|
10
|
+
|
11
|
+
Rake::TestTask.new do |t|
|
12
|
+
t.test_files = Dir["test/*_test.rb"]
|
13
|
+
end
|
14
|
+
|
15
|
+
Rake::RDocTask.new do |t|
|
16
|
+
t.title = "Core Documentation"
|
17
|
+
t.main = "README.rdoc"
|
18
|
+
t.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
19
|
+
t.rdoc_dir = "doc"
|
20
|
+
end
|
data/lib/core.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'core', 'module')
|
2
|
+
require File.join(File.dirname(__FILE__), 'core', 'object')
|
3
|
+
ruby_files = Dir.glob(File.join(File.dirname(__FILE__), 'core', '*.rb'))
|
4
|
+
ruby_files.each { |file| require file }
|
5
|
+
|
6
|
+
module Kinda #:nodoc:
|
7
|
+
# Basic helpers used by other kinda projects
|
8
|
+
module Core
|
9
|
+
include Accessor
|
10
|
+
include Forwardable
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Kinda #:nodoc:
|
2
|
+
module Core #:nodoc:
|
3
|
+
# Improves the Ruby buit-in accessor methods
|
4
|
+
module Accessor
|
5
|
+
ClassMethods = inheritable_extend do
|
6
|
+
def __attr_reader__(*attributes, with_filter, &block)
|
7
|
+
attributes.each do |attribute|
|
8
|
+
if attribute.is_a?(Hash)
|
9
|
+
attribute, source = attribute.first
|
10
|
+
else
|
11
|
+
source = "@#{attribute}"
|
12
|
+
end
|
13
|
+
proc = if with_filter || !block
|
14
|
+
Proc.new do |*args|
|
15
|
+
return send("#{attribute}=", *args) unless args.empty?
|
16
|
+
value = if source[0] == '@'
|
17
|
+
instance_variable_get(source)
|
18
|
+
else
|
19
|
+
[*source].inject(self) do |object, symbol|
|
20
|
+
object.send(symbol)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
block ? instance_exec(value, &block) : value
|
24
|
+
end
|
25
|
+
else
|
26
|
+
block
|
27
|
+
end
|
28
|
+
send(:define_method, attribute, &proc)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private :__attr_reader__
|
33
|
+
|
34
|
+
# attr_reader(:name, :age, :size)
|
35
|
+
# attr_reader(:name => :@name) is the default behaviour but you can use:
|
36
|
+
# attr_reader (:name => @the_name) to use a different instance variable
|
37
|
+
# attr_reader(:name => :first_name) or even an another attribute.
|
38
|
+
# More interesting, you can delegate to another object:
|
39
|
+
# attr_reader(:name => [:father, :name])
|
40
|
+
# attr_reader(:name => [:mother, :husband, :name])
|
41
|
+
def attr_reader(*attributes, &block)
|
42
|
+
__attr_reader__(*attributes, false, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def attr_reader_with_filter(*attributes, &block)
|
46
|
+
__attr_reader__(*attributes, true, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def __attr_writer__(*attributes, with_filter, &block)
|
50
|
+
attributes.each do |attribute|
|
51
|
+
if attribute.is_a?(Hash)
|
52
|
+
attribute, target = attribute.first
|
53
|
+
else
|
54
|
+
target = "@#{attribute}"
|
55
|
+
end
|
56
|
+
proc = if with_filter || !block
|
57
|
+
Proc.new do |value|
|
58
|
+
value = instance_exec(value, &block) if block
|
59
|
+
if target[0] == '@'
|
60
|
+
instance_variable_set(target, value)
|
61
|
+
else
|
62
|
+
[*target][0..-2].inject(self) do |object, symbol|
|
63
|
+
object.send(symbol)
|
64
|
+
end.send("#{[*target].last}=", value)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
else
|
68
|
+
block
|
69
|
+
end
|
70
|
+
send(:define_method, "#{attribute}=", &proc)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private :__attr_writer__
|
75
|
+
|
76
|
+
def attr_writer(*attributes, &block)
|
77
|
+
__attr_writer__(*attributes, false, &block)
|
78
|
+
end
|
79
|
+
|
80
|
+
def attr_writer_with_filter(*attributes, &block)
|
81
|
+
__attr_writer__(*attributes, true, &block)
|
82
|
+
end
|
83
|
+
|
84
|
+
def attr_accessor(*attributes, &block)
|
85
|
+
attr_reader(*attributes, &block)
|
86
|
+
attr_writer(*attributes, &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def attr_accessor_with_filter(*attributes, &block)
|
90
|
+
attr_reader_with_filter(*attributes, &block)
|
91
|
+
attr_writer_with_filter(*attributes, &block)
|
92
|
+
end
|
93
|
+
|
94
|
+
def attr(attribute, writable=false)
|
95
|
+
attr_reader(attribute)
|
96
|
+
attr_writer(attribute) if writable
|
97
|
+
end
|
98
|
+
|
99
|
+
def attr_reader_with_default(attribute, default_value)
|
100
|
+
attr_reader_with_filter(attribute) do |value|
|
101
|
+
value.nil? ? default_value : value
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def attr_accessor_with_default(attribute, default_value)
|
106
|
+
attr_reader_with_default(attribute, default_value)
|
107
|
+
attr_writer(attribute)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
delegate_to_class ClassMethods.public_instance_methods
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Kinda
|
4
|
+
module Core
|
5
|
+
module Forwardable
|
6
|
+
ClassMethods = inheritable_extend do
|
7
|
+
include ::Forwardable
|
8
|
+
|
9
|
+
# Add a nice way to specify a different method for the accessor:
|
10
|
+
# delegate :remove => [:book, :delete]
|
11
|
+
# delegate [:add, :remove] => [:book, :<<, :delete]
|
12
|
+
def instance_delegate(hash)
|
13
|
+
hash.each do |delegate_methods, accessor|
|
14
|
+
accessor_methods = [*accessor]
|
15
|
+
accessor_object = accessor_methods.shift
|
16
|
+
[*delegate_methods].each do |delegate_method|
|
17
|
+
accessor_method = accessor_methods.shift || delegate_method
|
18
|
+
def_instance_delegator(accessor_object, accessor_method, delegate_method)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :delegate, :instance_delegate
|
24
|
+
|
25
|
+
# Create both reader and writer delegate
|
26
|
+
# Same usage than the simple "delegate" method except the following form
|
27
|
+
# in case the getter and setter symbols are different:
|
28
|
+
# delegate_attr :title => [:book, [:read_title, :write_title]]
|
29
|
+
def delegate_attr_accessor(hash, kind=(:accessor), with_filter=false, &block)
|
30
|
+
hash.each do |delegate_methods, accessor|
|
31
|
+
accessor_methods = [*accessor]
|
32
|
+
accessor_object = accessor_methods.shift
|
33
|
+
[*delegate_methods].each do |delegate_method|
|
34
|
+
accessor_method = accessor_methods.shift || delegate_method
|
35
|
+
accessor_getter, accessor_setter = case kind
|
36
|
+
when :accessor
|
37
|
+
getter, setter = [*accessor_method]
|
38
|
+
setter ||= getter
|
39
|
+
[getter, setter]
|
40
|
+
when :reader
|
41
|
+
[accessor_method, nil]
|
42
|
+
when :writer
|
43
|
+
[nil, accessor_method]
|
44
|
+
end
|
45
|
+
if accessor_getter
|
46
|
+
__attr_reader__({ delegate_method => [accessor_object, accessor_getter] },
|
47
|
+
with_filter, &block)
|
48
|
+
end
|
49
|
+
if accessor_setter
|
50
|
+
__attr_writer__({ delegate_method => [accessor_object, accessor_setter] },
|
51
|
+
with_filter, &block)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
alias_method :delegate_attr, :delegate_attr_accessor
|
58
|
+
|
59
|
+
def delegate_attr_accessor_with_filter(hash, &block)
|
60
|
+
delegate_attr_accessor(hash, :accessor, true, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
alias_method :delegate_attr_with_filter, :delegate_attr_accessor_with_filter
|
64
|
+
|
65
|
+
def delegate_attr_reader(hash, &block)
|
66
|
+
delegate_attr_accessor(hash, :reader, false, &block)
|
67
|
+
end
|
68
|
+
|
69
|
+
def delegate_attr_reader_with_filter(hash, &block)
|
70
|
+
delegate_attr_accessor(hash, :reader, true, &block)
|
71
|
+
end
|
72
|
+
|
73
|
+
def delegate_attr_writer(hash, &block)
|
74
|
+
delegate_attr_accessor(hash, :writer, false, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def delegate_attr_writer_with_filter(hash, &block)
|
78
|
+
delegate_attr_accessor(hash, :writer, true, &block)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
delegate_to_class ClassMethods.public_instance_methods
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/core/functor.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
# Thomas Sawyer's Functor Class slightly modified for Ruby 1.9
|
4
|
+
# http://facets.rubyforge.org/apidoc/api/core/classes/Functor.html
|
5
|
+
class Functor < BasicObject
|
6
|
+
def initialize(&proc)
|
7
|
+
@proc = proc
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_proc
|
11
|
+
@proc
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(method_name, *args, &block)
|
15
|
+
@proc.call(method_name, *args, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/core/hash.rb
ADDED
data/lib/core/inspect.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
def inspect(*args)
|
4
|
+
if %w[Bignum Class Complex Date DateTime FalseClass Fixnum Float
|
5
|
+
Integer NilClass Numeric Range Rational Regexp String Symbol
|
6
|
+
Time TrueClass].include?(self.class.name)
|
7
|
+
super()
|
8
|
+
else
|
9
|
+
result = '#<'
|
10
|
+
result += "#{self.class}:#{object_hexid}"
|
11
|
+
items = args.map do |arg|
|
12
|
+
"#{arg}=#{send(arg).inspect}" if respond_to?(arg)
|
13
|
+
end.compact
|
14
|
+
result += ' ' + items.join(', ') if !items.empty?
|
15
|
+
result += '>'
|
16
|
+
result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/core/module.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
module ModuleExtension
|
4
|
+
def self.included(klass)
|
5
|
+
klass.alias_method_chain :append_features, :inheritable_extensions
|
6
|
+
end
|
7
|
+
|
8
|
+
def alias_method_chain(target, feature)
|
9
|
+
# Strip out punctuation on predicates or bang methods since
|
10
|
+
# e.g. target?_without_feature is not a valid method name.
|
11
|
+
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
|
12
|
+
yield(aliased_target, punctuation) if block_given?
|
13
|
+
|
14
|
+
with_method, without_method =
|
15
|
+
"#{aliased_target}_with_#{feature}#{punctuation}",
|
16
|
+
"#{aliased_target}_without_#{feature}#{punctuation}"
|
17
|
+
|
18
|
+
alias_method without_method, target
|
19
|
+
alias_method target, with_method
|
20
|
+
|
21
|
+
case
|
22
|
+
when public_method_defined?(without_method)
|
23
|
+
public target
|
24
|
+
when protected_method_defined?(without_method)
|
25
|
+
protected target
|
26
|
+
when private_method_defined?(without_method)
|
27
|
+
private target
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def container
|
32
|
+
space = name[0...(name.rindex( '::' ) || 0)]
|
33
|
+
space.empty? ? Object : eval(space)
|
34
|
+
end
|
35
|
+
|
36
|
+
def extensions
|
37
|
+
singleton_class.ancestors.take_while { |mod| !mod.is_a?(Class) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def inheritable_extend(*mods, &block)
|
41
|
+
if block
|
42
|
+
mod = Module.new
|
43
|
+
mod.extend extensions
|
44
|
+
mod.module_eval(&block)
|
45
|
+
mods << mod
|
46
|
+
end
|
47
|
+
extend *mods
|
48
|
+
(@inheritable_extensions ||= []).unshift(*mods.reverse).uniq!
|
49
|
+
mod
|
50
|
+
end
|
51
|
+
|
52
|
+
def append_features_with_inheritable_extensions(target)
|
53
|
+
append_features_without_inheritable_extensions(target)
|
54
|
+
if @inheritable_extensions
|
55
|
+
target.extend *@inheritable_extensions
|
56
|
+
target.inheritable_extend *@inheritable_extensions.reverse
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# delegate_to_class :singleton_method_added => :method_added
|
61
|
+
# delegate_to_class [:attr_reader, :attr_writer]
|
62
|
+
# delegate_to_class ClassMethods.instance_methods
|
63
|
+
def delegate_to_class(*sources)
|
64
|
+
sources, target = sources.first.first if sources.first.is_a?(Hash)
|
65
|
+
[*sources].flatten.each do |source|
|
66
|
+
define_method(source) do |*args, &block|
|
67
|
+
singleton_class_send(target || source, *args, &block)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self_and_ancestors
|
73
|
+
result = ancestors
|
74
|
+
result.unshift self unless result.first == self
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
def ancestors_without_self
|
79
|
+
result = ancestors
|
80
|
+
result.first == self ? result.drop(1) : result
|
81
|
+
end
|
82
|
+
|
83
|
+
def ancestor
|
84
|
+
ancestors_without_self.first
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Module #:nodoc:
|
91
|
+
include Kinda::Core::ModuleExtension
|
92
|
+
end
|
93
|
+
|
data/lib/core/object.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
module ObjectExtension
|
4
|
+
def self.included(klass)
|
5
|
+
klass.alias_method_chain :extend, :flexible_arguments
|
6
|
+
end
|
7
|
+
|
8
|
+
def object_hexid
|
9
|
+
"0x" + ('%.x' % (self.__id__ * 2))
|
10
|
+
end
|
11
|
+
|
12
|
+
def singleton_class
|
13
|
+
class << self; self; end
|
14
|
+
end
|
15
|
+
|
16
|
+
def singleton_class_eval(&block)
|
17
|
+
singleton_class.class_eval(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def singleton_class_send(method_name, *args, &block)
|
21
|
+
singleton_class_eval { send(method_name, *args, &block) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_class
|
25
|
+
kind_of?(Module) ? self : singleton_class
|
26
|
+
end
|
27
|
+
|
28
|
+
alias_method :to_module, :to_class
|
29
|
+
|
30
|
+
def extend_with_flexible_arguments(*modules)
|
31
|
+
mods = modules.flatten
|
32
|
+
extend_without_flexible_arguments(*mods) unless mods.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
def tap
|
36
|
+
return super if block_given?
|
37
|
+
Functor.new { |method, *args| self.send(method, *args); self }
|
38
|
+
end
|
39
|
+
|
40
|
+
def try(method_name, *args, &block)
|
41
|
+
send(method_name, *args, &block) if respond_to?(method_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def receiver
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_method :__instance_exec__, :instance_exec
|
49
|
+
|
50
|
+
def parse_arguments(args, *defaults)
|
51
|
+
args = args.dup
|
52
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
53
|
+
raise ArgumentError, "Too many arguments (#{args.size} for #{defaults.size})" if
|
54
|
+
args.size > defaults.size
|
55
|
+
defaults.drop(args.size).each { |default| args << default }
|
56
|
+
args << options
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Object #:nodoc:
|
63
|
+
include Kinda::Core::ObjectExtension
|
64
|
+
end
|
data/lib/core/this.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
module This
|
4
|
+
module ProcExtension
|
5
|
+
def call_with_this(this, *args, &block)
|
6
|
+
binding_self = binding.eval('self')
|
7
|
+
binding_self.push_this(this)
|
8
|
+
call(*args, &block)
|
9
|
+
ensure
|
10
|
+
binding_self.pop_this
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
###
|
15
|
+
|
16
|
+
def call_with_this(proc, *args, &block)
|
17
|
+
return unless proc
|
18
|
+
binding_self = proc.binding.eval('self')
|
19
|
+
raise "Object #{binding_self.inspect} doesn't respond to Kinda::Core::This methods " +
|
20
|
+
"(proc=#{proc.inspect})" unless binding_self.respond_to?(:push_this)
|
21
|
+
begin
|
22
|
+
binding_self.push_this(self)
|
23
|
+
proc.call(*args, &block)
|
24
|
+
ensure
|
25
|
+
binding_self.pop_this
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def push_this(object)
|
30
|
+
(@these ||= []).push(object)
|
31
|
+
end
|
32
|
+
|
33
|
+
def pop_this
|
34
|
+
@these.pop if @these
|
35
|
+
end
|
36
|
+
|
37
|
+
def this
|
38
|
+
(@these && @these.last) || self
|
39
|
+
end
|
40
|
+
|
41
|
+
def this_eval(&block)
|
42
|
+
this.instance_eval(&block)
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :contextual_methods
|
46
|
+
|
47
|
+
def contextual_method(*methods)
|
48
|
+
methods.each do |method|
|
49
|
+
(@contextual_methods ||= []) << method.to_sym
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def contextual_method?(method)
|
54
|
+
to_class.self_and_ancestors.each do |ancestor|
|
55
|
+
return true if ancestor.contextual_methods &&
|
56
|
+
ancestor.contextual_methods.include?(method.to_sym)
|
57
|
+
end
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
def method_missing(method_name, *args, &block)
|
62
|
+
if this != self && this.contextual_method?(method_name)
|
63
|
+
this.send(method_name, *args, &block)
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Object #:nodoc:
|
73
|
+
include Kinda::Core::This
|
74
|
+
end
|
75
|
+
|
76
|
+
class Proc #:nodoc:
|
77
|
+
include Kinda::Core::This::ProcExtension
|
78
|
+
end
|
data/lib/kinda-core.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'core')
|
data/test/__all__.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/ruby19
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')).uniq!
|
7
|
+
require 'kinda-core'
|
8
|
+
|
9
|
+
class AccessorTest < Test::Unit::TestCase
|
10
|
+
def setup
|
11
|
+
@human_class = Class.new do
|
12
|
+
include Kinda::Core
|
13
|
+
end
|
14
|
+
@human = @human_class.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_attribute_defined_at_class_level
|
18
|
+
@human_class.class_eval do
|
19
|
+
attr_accessor :name
|
20
|
+
end
|
21
|
+
assert_nil @human.name
|
22
|
+
@human.name = 'Dave'
|
23
|
+
assert_equal 'Dave', @human.name
|
24
|
+
@human.name 'Fred'
|
25
|
+
assert_equal 'Fred', @human.name
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_attribute_defined_at_instance_level
|
29
|
+
@human.attr_accessor :name
|
30
|
+
assert_nil @human.name
|
31
|
+
@human.name = 'Dave'
|
32
|
+
assert_equal 'Dave', @human.name
|
33
|
+
@human.name 'Fred'
|
34
|
+
assert_equal 'Fred', @human.name
|
35
|
+
@other_human = @human_class.new
|
36
|
+
assert_raise NoMethodError do
|
37
|
+
@other_human.name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_attribute_with_block_defined_at_class_level
|
42
|
+
@human_class.class_eval do
|
43
|
+
attr_reader :name do |capitalize=false|
|
44
|
+
capitalize ? @the_name.capitalize : @the_name
|
45
|
+
end
|
46
|
+
attr_writer :name do |value|
|
47
|
+
@the_name = value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
assert_equal nil, @human.name
|
51
|
+
@human.name = 'Dave'
|
52
|
+
assert_equal 'Dave', @human.name
|
53
|
+
@human.name = 'fred'
|
54
|
+
assert_equal 'Fred', @human.name(true)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_attribute_with_filter_defined_at_class_level
|
58
|
+
@human_class.class_eval do
|
59
|
+
attr_accessor :nickname
|
60
|
+
|
61
|
+
attr_reader_with_filter :name do |value|
|
62
|
+
value || nickname || 'Mike'
|
63
|
+
end
|
64
|
+
attr_writer_with_filter :name do |value|
|
65
|
+
value.capitalize
|
66
|
+
end
|
67
|
+
end
|
68
|
+
assert_equal 'Mike', @human.name
|
69
|
+
@human.nickname = 'Mikey'
|
70
|
+
assert_equal 'Mikey', @human.name
|
71
|
+
@human.name = 'dave'
|
72
|
+
assert_equal 'Dave', @human.name
|
73
|
+
@human.name 'FRED'
|
74
|
+
assert_equal 'Fred', @human.name
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_attribute_redirection
|
78
|
+
@human.attr_accessor :name => :@the_name
|
79
|
+
assert_nil @human.name
|
80
|
+
@human.name = 'Dave'
|
81
|
+
assert_equal 'Dave', @human.name
|
82
|
+
assert_equal 'Dave', @human.instance_variable_get(:@the_name)
|
83
|
+
@human.name = 'Fred'
|
84
|
+
assert_equal 'Fred', @human.name
|
85
|
+
@human.attr_accessor :last_name => :name
|
86
|
+
assert_equal 'Fred', @human.last_name
|
87
|
+
@human.last_name = 'Mike'
|
88
|
+
assert_equal 'Mike', @human.last_name
|
89
|
+
assert_equal 'Mike', @human.name
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_attribute_delegation
|
93
|
+
@child = @human_class.new
|
94
|
+
@father = @human_class.new
|
95
|
+
@child.attr_accessor :father
|
96
|
+
@child.father = @father
|
97
|
+
assert_equal @father, @child.father
|
98
|
+
@father.attr_accessor :name
|
99
|
+
@father.name = 'Dave'
|
100
|
+
@child.attr_accessor :name => [:father, :name]
|
101
|
+
assert_equal 'Dave', @child.name
|
102
|
+
@child.name = 'Fred'
|
103
|
+
assert_equal 'Fred', @child.name
|
104
|
+
assert_equal 'Fred', @father.name
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_attribute_double_delegation
|
108
|
+
@child = @human_class.new
|
109
|
+
@mother = @human_class.new
|
110
|
+
@husband = @human_class.new
|
111
|
+
@child.attr_accessor :mother
|
112
|
+
@child.mother = @mother
|
113
|
+
@mother.attr_accessor :husband
|
114
|
+
@mother.husband = @husband
|
115
|
+
assert_equal @husband, @child.mother.husband
|
116
|
+
@husband.attr_accessor :name
|
117
|
+
@husband.name = 'Dave'
|
118
|
+
@child.attr_accessor :name => [:mother, :husband, :name]
|
119
|
+
assert_equal 'Dave', @child.name
|
120
|
+
@child.name = 'Fred'
|
121
|
+
assert_equal 'Fred', @child.name
|
122
|
+
assert_equal 'Fred', @husband.name
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_attribute_with_default
|
126
|
+
@human.attr_accessor_with_default :name, 'Bart'
|
127
|
+
assert_equal 'Bart', @human.name
|
128
|
+
@human.name = 'Dave'
|
129
|
+
assert_equal 'Dave', @human.name
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/ruby19
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')).uniq!
|
7
|
+
require 'kinda-core'
|
8
|
+
|
9
|
+
class ForwardableTest < Test::Unit::TestCase
|
10
|
+
def setup
|
11
|
+
@human_class = Class.new do
|
12
|
+
include Kinda::Core
|
13
|
+
end
|
14
|
+
@human = @human_class.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_delegate_attribute
|
18
|
+
@child = @human_class.new
|
19
|
+
@father = @human_class.new
|
20
|
+
@child.attr_accessor :father
|
21
|
+
@child.father = @father
|
22
|
+
assert_equal @father, @child.father
|
23
|
+
@father.attr_accessor :name
|
24
|
+
@father.name = 'Dave'
|
25
|
+
@child.delegate_attr :name => :father
|
26
|
+
assert_equal 'Dave', @child.name
|
27
|
+
@child.name = 'Fred'
|
28
|
+
assert_equal 'Fred', @child.name
|
29
|
+
assert_equal 'Fred', @father.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_delegate_attribute_with_filter
|
33
|
+
@child = @human_class.new
|
34
|
+
@father = @human_class.new
|
35
|
+
@child.attr_accessor :father
|
36
|
+
@child.father = @father
|
37
|
+
assert_equal @father, @child.father
|
38
|
+
@father.attr_accessor :name
|
39
|
+
@father.name = 'Dave'
|
40
|
+
@child.delegate_attr_reader_with_filter :name => :father do |value|
|
41
|
+
value + ' junior'
|
42
|
+
end
|
43
|
+
assert_equal 'Dave junior', @child.name
|
44
|
+
@child.delegate_attr_writer_with_filter :name => :father do |value|
|
45
|
+
value.capitalize
|
46
|
+
end
|
47
|
+
@child.name = 'fred'
|
48
|
+
assert_equal 'Fred junior', @child.name
|
49
|
+
assert_equal 'Fred', @father.name
|
50
|
+
end
|
51
|
+
end
|
data/test/module_test.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/ruby19
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')).uniq!
|
7
|
+
require 'kinda-core'
|
8
|
+
|
9
|
+
class ModuleTest < Test::Unit::TestCase
|
10
|
+
def meth
|
11
|
+
'meth'
|
12
|
+
end
|
13
|
+
|
14
|
+
def meth_with_upcase
|
15
|
+
meth_without_upcase.upcase
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method_chain :meth, :upcase
|
19
|
+
|
20
|
+
def test_alias_method_chain
|
21
|
+
assert_equal 'METH', meth
|
22
|
+
end
|
23
|
+
|
24
|
+
$meth2 = []
|
25
|
+
|
26
|
+
module A
|
27
|
+
module ClassMethods1
|
28
|
+
def meth1
|
29
|
+
'meth1'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods2
|
34
|
+
def meth2
|
35
|
+
$meth2 << 'ClassMethods2.meth2'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
inheritable_extend ClassMethods1, ClassMethods2
|
40
|
+
end
|
41
|
+
|
42
|
+
module B
|
43
|
+
include A
|
44
|
+
|
45
|
+
ClassMethods3 = inheritable_extend do
|
46
|
+
$meth1 = meth1
|
47
|
+
|
48
|
+
def meth3
|
49
|
+
'meth3'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module ClassMethods4
|
54
|
+
def meth2
|
55
|
+
super
|
56
|
+
$meth2 << 'ClassMethods4.meth2'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
inheritable_extend ClassMethods4
|
61
|
+
end
|
62
|
+
|
63
|
+
class X
|
64
|
+
include B
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_container
|
68
|
+
assert_equal ModuleTest::A, ModuleTest::A::ClassMethods1.container
|
69
|
+
assert_equal ModuleTest::B, ModuleTest::B::ClassMethods3.container
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_extensions
|
73
|
+
assert_equal [ModuleTest::B::ClassMethods4, ModuleTest::B::ClassMethods3,
|
74
|
+
ModuleTest::A::ClassMethods2, ModuleTest::A::ClassMethods1], X.extensions
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_inheritable_extend
|
78
|
+
assert_equal 'meth1', $meth1
|
79
|
+
X.meth2
|
80
|
+
assert_equal ["ClassMethods2.meth2", "ClassMethods4.meth2"], $meth2
|
81
|
+
assert_equal 'meth1', X.meth1
|
82
|
+
assert_equal 'meth3', X.meth3
|
83
|
+
end
|
84
|
+
end
|
data/test/object_test.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/ruby19
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')).uniq!
|
7
|
+
require 'kinda-core'
|
8
|
+
|
9
|
+
class ObjectTest < Test::Unit::TestCase
|
10
|
+
def test_tap
|
11
|
+
assert_equal 'Hello', 'Hello'.tap { |str| assert_equal 'HELLO', str.upcase }
|
12
|
+
assert_equal 'Hello', 'Hello'.tap.upcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_try
|
16
|
+
assert_equal nil, 'Hello'.try(:undefined)
|
17
|
+
assert_equal 'HELLO', 'Hello'.try(:upcase)
|
18
|
+
assert_equal 'hello', 'Hello'.try(:upcase).try(:downcase)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_parse_arguments
|
22
|
+
assert_equal [1, 2, {}], parse_arguments([], 1, 2)
|
23
|
+
assert_equal [3, 4, {}], parse_arguments([3, 4], 1, 2)
|
24
|
+
assert_raise(ArgumentError) { parse_arguments([3, 4, 5], 1, 2) }
|
25
|
+
assert_equal [1, 2, {:a => 'c', :b => 'd'}], parse_arguments([:a => 'c', :b => 'd'], 1, 2)
|
26
|
+
assert_equal [3, 2, {:a => 'c', :b => 'd'}], parse_arguments([3, :a => 'c', :b => 'd'], 1, 2)
|
27
|
+
end
|
28
|
+
end
|
data/test/this_test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Manuel Vila
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-12 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Basic helpers used by other kinda projects
|
17
|
+
email: mvila@3base.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- lib/core.rb
|
27
|
+
- lib/kinda-core.rb
|
28
|
+
- lib/core/accessor.rb
|
29
|
+
- lib/core/forwardable.rb
|
30
|
+
- lib/core/functor.rb
|
31
|
+
- lib/core/hash.rb
|
32
|
+
- lib/core/inspect.rb
|
33
|
+
- lib/core/module.rb
|
34
|
+
- lib/core/object.rb
|
35
|
+
- lib/core/this.rb
|
36
|
+
- README.rdoc
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/kinda/core
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 1.9.1
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project: kinda-core
|
61
|
+
rubygems_version: 1.3.5
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Basic helpers used by other kinda projects
|
65
|
+
test_files:
|
66
|
+
- test/__all__.rb
|
67
|
+
- test/accessor_test.rb
|
68
|
+
- test/forwardable_test.rb
|
69
|
+
- test/module_test.rb
|
70
|
+
- test/object_test.rb
|
71
|
+
- test/this_test.rb
|