kinda-core 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +14 -0
- data/lib/core/accessor.rb +110 -0
- data/lib/core/forwardable.rb +86 -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 +81 -0
- data/lib/core/object.rb +63 -0
- data/lib/core/proc.rb +17 -0
- data/lib/core/this.rb +62 -0
- data/lib/core.rb +10 -0
- data/lib/kinda-core.rb +1 -0
- metadata +65 -0
data/README.rdoc
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Author:: Manuel Vila (mailto:mvila@3base.com)
|
2
|
+
License:: Don't know yet
|
3
|
+
|
4
|
+
= Core
|
5
|
+
|
6
|
+
Basic helpers used by other kinda projects.
|
7
|
+
|
8
|
+
== Installation
|
9
|
+
|
10
|
+
$ sudo gem install kinda-core --source http://gems.github.com
|
11
|
+
|
12
|
+
== Usage
|
13
|
+
|
14
|
+
Still very alpha so documentation will come later.
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
module Accessor
|
4
|
+
module ClassMethods
|
5
|
+
# attr_reader(:name, :age, :size)
|
6
|
+
# attr_reader(:name => :@name) is the default behaviour but you can use:
|
7
|
+
# attr_reader (:name => @the_name) to use a different instance variable
|
8
|
+
# attr_reader(:name => :first_name) or even an another attribute.
|
9
|
+
# But more interesting, you can delegate to another object:
|
10
|
+
# attr_reader(:name => [:father, :name])
|
11
|
+
# attr_reader(:name => [:mother, :husband, :name])
|
12
|
+
def __attr_reader__(*attributes, with_filter, &block)
|
13
|
+
attributes.each do |attribute|
|
14
|
+
if attribute.is_a?(Hash)
|
15
|
+
attribute, source = attribute.first
|
16
|
+
else
|
17
|
+
source = "@#{attribute}"
|
18
|
+
end
|
19
|
+
proc = if with_filter || !block
|
20
|
+
::Proc.new do |*args|
|
21
|
+
return send("#{attribute}=", *args) unless args.empty?
|
22
|
+
value = if source[0] == '@'
|
23
|
+
instance_variable_get(source)
|
24
|
+
else
|
25
|
+
[*source].inject(self) do |object, symbol|
|
26
|
+
object.send(symbol)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
block ? instance_exec(value, &block) : value
|
30
|
+
end
|
31
|
+
else
|
32
|
+
block
|
33
|
+
end
|
34
|
+
to_class.send(:define_method, attribute, &proc)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def attr_reader(*attributes, &block)
|
39
|
+
__attr_reader__(*attributes, false, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def attr_reader_with_filter(*attributes, &block)
|
43
|
+
__attr_reader__(*attributes, true, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def __attr_writer__(*attributes, with_filter, &block)
|
47
|
+
attributes.each do |attribute|
|
48
|
+
if attribute.is_a?(Hash)
|
49
|
+
attribute, target = attribute.first
|
50
|
+
else
|
51
|
+
target = "@#{attribute}"
|
52
|
+
end
|
53
|
+
proc = if with_filter || !block
|
54
|
+
::Proc.new do |value|
|
55
|
+
value = instance_exec(value, &block) if block
|
56
|
+
if target[0] == '@'
|
57
|
+
instance_variable_set(target, value)
|
58
|
+
else
|
59
|
+
[*target][0..-2].inject(self) do |object, symbol|
|
60
|
+
object.send(symbol)
|
61
|
+
end.send("#{[*target].last}=", value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
else
|
65
|
+
block
|
66
|
+
end
|
67
|
+
to_class.send(:define_method, "#{attribute}=", &proc)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def attr_writer(*attributes, &block)
|
72
|
+
__attr_writer__(*attributes, false, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
def attr_writer_with_filter(*attributes, &block)
|
76
|
+
__attr_writer__(*attributes, true, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def attr_accessor(*attributes, &block)
|
80
|
+
attr_reader(*attributes, &block)
|
81
|
+
attr_writer(*attributes, &block)
|
82
|
+
end
|
83
|
+
|
84
|
+
def attr_accessor_with_filter(*attributes, &block)
|
85
|
+
attr_reader_with_filter(*attributes, &block)
|
86
|
+
attr_writer_with_filter(*attributes, &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def attr(attribute, writable=false)
|
90
|
+
attr_reader(attribute)
|
91
|
+
attr_writer(attribute) if writable
|
92
|
+
end
|
93
|
+
|
94
|
+
def attr_reader_with_default(attribute, default_value)
|
95
|
+
attr_reader_with_filter(attribute) do |value|
|
96
|
+
value.nil? ? default_value : value
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def attr_accessor_with_default(attribute, default_value)
|
101
|
+
attr_reader_with_default(attribute, default_value)
|
102
|
+
attr_writer(attribute)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
include ClassMethods
|
107
|
+
inheritable_extension ClassMethods
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Kinda
|
4
|
+
module Core
|
5
|
+
module Forwardable
|
6
|
+
module ClassMethods
|
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
|
+
include ClassMethods
|
83
|
+
inheritable_extension ClassMethods
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/core/functor.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Thomas Sawyer's Functor Class slightly modified for Ruby 1.9
|
2
|
+
# http://facets.rubyforge.org/apidoc/api/core/classes/Functor.html
|
3
|
+
module Kinda
|
4
|
+
module Core
|
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,81 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
module Module
|
4
|
+
def self.included(klass)
|
5
|
+
klass.alias_method_chain :append_features, :module_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_extension(*mods)
|
41
|
+
(@inheritable_extensions ||= []).unshift(mods.reverse).flatten!.uniq!
|
42
|
+
end
|
43
|
+
|
44
|
+
def append_features_with_module_extensions(target)
|
45
|
+
append_features_without_module_extensions(target)
|
46
|
+
if @inheritable_extensions
|
47
|
+
target.extend *@inheritable_extensions
|
48
|
+
target.inheritable_extension *@inheritable_extensions.reverse
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def delegate_to_class(source, target=source)
|
53
|
+
define_method(source) do |*args, &block|
|
54
|
+
singleton_class_eval do
|
55
|
+
send(target, *args, &block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self_and_ancestors
|
61
|
+
result = ancestors
|
62
|
+
result.unshift self unless result.first == self
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
66
|
+
def ancestors_without_self
|
67
|
+
result = ancestors
|
68
|
+
result.first == self ? result.drop(1) : result
|
69
|
+
end
|
70
|
+
|
71
|
+
def ancestor
|
72
|
+
ancestors_without_self.first
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Module
|
79
|
+
include Kinda::Core::Module
|
80
|
+
end
|
81
|
+
|
data/lib/core/object.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
module Object
|
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 to_class
|
21
|
+
kind_of?(Module) ? self : singleton_class
|
22
|
+
end
|
23
|
+
|
24
|
+
alias_method :to_module, :to_class
|
25
|
+
|
26
|
+
def extend_with_flexible_arguments(*modules)
|
27
|
+
mods = modules.flatten
|
28
|
+
extend_without_flexible_arguments(*mods) unless mods.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
def tap
|
32
|
+
return super if block_given?
|
33
|
+
Functor.new { |method, *args| self.send(method, *args); self }
|
34
|
+
end
|
35
|
+
|
36
|
+
def try(methods, *args, &block)
|
37
|
+
methods = [*methods].dup
|
38
|
+
return self if methods.empty?
|
39
|
+
send(methods.shift, *args, &block).try(methods, *args, &block) if
|
40
|
+
respond_to?(methods.first)
|
41
|
+
end
|
42
|
+
|
43
|
+
def receiver
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :__instance_exec__, :instance_exec
|
48
|
+
|
49
|
+
def parse_arguments(args, *defaults)
|
50
|
+
args = args.dup
|
51
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
52
|
+
raise ArgumentError, "Too many arguments (#{args.size} for #{defaults.size})" if
|
53
|
+
args.size > defaults.size
|
54
|
+
defaults.drop(args.size).each { |default| args << default }
|
55
|
+
args << options
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class Object
|
62
|
+
include Kinda::Core::Object
|
63
|
+
end
|
data/lib/core/proc.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
module Proc
|
4
|
+
def call_with_this(this, *args, &block)
|
5
|
+
binding_self = binding.eval('self')
|
6
|
+
binding_self.push_this(this)
|
7
|
+
call(*args, &block)
|
8
|
+
ensure
|
9
|
+
binding_self.pop_this
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Proc
|
16
|
+
include Kinda::Core::Proc
|
17
|
+
end
|
data/lib/core/this.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
module Kinda
|
2
|
+
module Core
|
3
|
+
module This
|
4
|
+
def call_with_this(proc, *args, &block)
|
5
|
+
return unless proc
|
6
|
+
binding_self = proc.binding.eval('self')
|
7
|
+
raise "Object #{binding_self.inspect} doesn't respond to Kinda::Core::This methods " +
|
8
|
+
"(proc=#{proc.inspect})" unless binding_self.respond_to?(:push_this)
|
9
|
+
begin
|
10
|
+
binding_self.push_this(self)
|
11
|
+
proc.call(*args, &block)
|
12
|
+
ensure
|
13
|
+
binding_self.pop_this
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def push_this(object)
|
18
|
+
(@these ||= []).push(object)
|
19
|
+
end
|
20
|
+
|
21
|
+
def pop_this
|
22
|
+
@these.pop if @these
|
23
|
+
end
|
24
|
+
|
25
|
+
def this
|
26
|
+
(@these && @these.last) || self
|
27
|
+
end
|
28
|
+
|
29
|
+
def this_eval(&block)
|
30
|
+
this.instance_eval(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :contextual_methods
|
34
|
+
|
35
|
+
def contextual_method(*methods)
|
36
|
+
methods.each do |method|
|
37
|
+
(@contextual_methods ||= []) << method.to_sym
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def contextual_method?(method)
|
42
|
+
to_class.self_and_ancestors.each do |ancestor|
|
43
|
+
return true if ancestor.contextual_methods &&
|
44
|
+
ancestor.contextual_methods.include?(method.to_sym)
|
45
|
+
end
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(method_name, *args, &block)
|
50
|
+
if this != self && this.contextual_method?(method_name)
|
51
|
+
this.send(method_name, *args, &block)
|
52
|
+
else
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Object
|
61
|
+
include Kinda::Core::This
|
62
|
+
end
|
data/lib/core.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'kinda-core', 'module')
|
2
|
+
ruby_files = Dir.glob(File.join(File.dirname(__FILE__), 'kinda-core', '*.rb'))
|
3
|
+
ruby_files.each { |file| require file }
|
4
|
+
|
5
|
+
module Kinda
|
6
|
+
module Core
|
7
|
+
include Accessor
|
8
|
+
include Forwardable
|
9
|
+
end
|
10
|
+
end
|
data/lib/kinda-core.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'core')
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kinda-core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Manuel Vila
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-16 00:00:00 -07: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
|
+
- lib/core.rb
|
26
|
+
- lib/core/accessor.rb
|
27
|
+
- lib/core/forwardable.rb
|
28
|
+
- lib/core/functor.rb
|
29
|
+
- lib/core/hash.rb
|
30
|
+
- lib/core/inspect.rb
|
31
|
+
- lib/core/module.rb
|
32
|
+
- lib/core/object.rb
|
33
|
+
- lib/core/proc.rb
|
34
|
+
- lib/core/this.rb
|
35
|
+
- lib/kinda-core.rb
|
36
|
+
- README.rdoc
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/kinda/core
|
39
|
+
licenses:
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project: kinda-core
|
60
|
+
rubygems_version: 1.3.5
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: Basic helpers used by other kinda projects
|
64
|
+
test_files: []
|
65
|
+
|