lab42_core 0.3.3 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +42 -7
- data/lib/lab42/core/b.rb +5 -2
- data/lib/lab42/core/behavior/bound_behavior.rb +41 -0
- data/lib/lab42/core/behavior/composition.rb +31 -0
- data/lib/lab42/core/behavior/negation.rb +13 -0
- data/lib/lab42/core/behavior/proc_behavior.rb +23 -0
- data/lib/lab42/core/behavior/proxy.rb +6 -6
- data/lib/lab42/core/behavior/send_behavior.rb +36 -0
- data/lib/lab42/core/behavior/unbound_behavior.rb +53 -0
- data/lib/lab42/core/behavior.rb +9 -34
- data/lib/lab42/core/dir.rb +3 -3
- data/lib/lab42/core/fn.rb +1 -1
- data/lib/lab42/core/hash.rb +15 -10
- data/lib/lab42/core/kernel.rb +10 -0
- data/lib/lab42/core/memoization.rb +22 -17
- data/lib/lab42/core/meta/behavior.rb +34 -0
- data/lib/lab42/core/meta/hash.rb +50 -0
- data/lib/lab42/core/meta.rb +1 -27
- data/lib/lab42/core/open_object.rb +8 -0
- data/lib/lab42/core/version.rb +1 -1
- data/lib/lab42/core.rb +1 -0
- metadata +11 -5
- data/lib/lab42/core/behave.rb +0 -0
- data/lib/lab42/core/unbound_behavior.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a45782982c7efdf61bb0193996363a204b8ee05
|
4
|
+
data.tar.gz: cd38beb0ab0b09bf8db7fc185089ff89880b02db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 058204661c72349652027840bc10509e9724cf6abe528ad5d4d0f90a1d022204c9f8542ff07d25ddeb6bf1186abbc026573a9edab2a51ae12d7634f186a2f658
|
7
|
+
data.tar.gz: a7464e37bf5228c2bb75981bf18c047e3d84e90b5ddfa0701f59788aa4ba02069c7f65013a728ef69aeefe646cd8ae2c6e3e77f1396075b640df945b931c4928
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ API will remain the same, require will change to `require 'lab42_more/fn'`
|
|
23
23
|
##### fn like function
|
24
24
|
|
25
25
|
```ruby
|
26
|
-
Dir.files [APP_ROOT, 'spec', 'support', '**', '*.rb'], Kernel.fn.require
|
26
|
+
Dir.files [APP_ROOT, 'spec', 'support', '**', '*.rb'], &Kernel.fn.require
|
27
27
|
|
28
28
|
Dir.files( %w{.. assets ** *.txt} ).sort_by &File.fn.mtime
|
29
29
|
```
|
@@ -40,20 +40,30 @@ upon call, once it has been transformed by `#to_proc`
|
|
40
40
|
|
41
41
|
For details see the corresponding [QED demo](https://github.com/RobertDober/lab42_core/blob/master/demo/fn.md).
|
42
42
|
|
43
|
-
|
43
|
+
#### Behave or B for Message Sending
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
This is a more general approach than `fn` or `fm` as we do not even know the class of the future receiver of the
|
46
|
+
message.
|
47
47
|
|
48
|
-
|
48
|
+
The subtle difference can be made clear with an example
|
49
49
|
|
50
|
-
|
50
|
+
```ruby
|
51
|
+
adder = B( :+ )
|
52
|
+
# can be used for Fixnums
|
53
|
+
adder.(1,41) # --> 42
|
54
|
+
# or Arrays
|
55
|
+
adder.(%w/a b/, %w&c d&) #--> %w%a b c d%
|
56
|
+
```
|
51
57
|
|
52
|
-
|
58
|
+
Which can of course not be accomplished by `Fixnum.fm.+`
|
53
59
|
|
54
60
|
|
55
61
|
For details see the corresponding [QED demo](https://github.com/RobertDober/lab42_core/blob/master/demo/behave.md).
|
56
62
|
|
63
|
+
#### All Behavior is Composable
|
64
|
+
|
65
|
+
The above methods all return instances of `Behavior` and `Behavor` has a much richer API than Ruby's core _callables_ like `Proc` or `Method`
|
66
|
+
|
57
67
|
#### Memoization and Lazy Attributes
|
58
68
|
|
59
69
|
##### Memoization
|
@@ -254,6 +264,31 @@ are provided (after all there is a !).
|
|
254
264
|
|
255
265
|
For details see the corresponding [QED demo](https://github.com/RobertDober/lab42_core/blob/master/demo/hash.md).
|
256
266
|
|
267
|
+
#### replace_rec
|
268
|
+
|
269
|
+
Recursive Replacement
|
270
|
+
|
271
|
+
##### Original Object untouched of course
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
|
275
|
+
a = {a: 42, x: {a: 43}}
|
276
|
+
b = a.replace_rec( :a, &:succ )
|
277
|
+
a.assert == {a: 42, x: {a: 43}}
|
278
|
+
b.assert == {a: 43, x: {a: 44}}
|
279
|
+
|
280
|
+
```
|
281
|
+
|
282
|
+
For bulk replacements and how to specify limits, please refer to [QED demo](https://github.com/RobertDober/lab42_core/blob/master/demo/hash.md).
|
283
|
+
|
284
|
+
#### without
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
h = {a: 1, b: 2, c: 3}
|
288
|
+
|
289
|
+
h.without( :b, :c, :d ).assert == {a: 1}
|
290
|
+
h.assert == {a: 1, b: 2, c: 3}
|
291
|
+
```
|
257
292
|
|
258
293
|
### Object
|
259
294
|
|
data/lib/lab42/core/b.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'forwarder'
|
2
|
+
require_relative 'composition'
|
3
|
+
module Lab42
|
4
|
+
module Behavior
|
5
|
+
# Thank youn my dear Proxy, for sending me all the information
|
6
|
+
# I, the clever guy, who is having all the fun, will make best
|
7
|
+
# use of it by being an extremly, yes I said *extremly* clever
|
8
|
+
# callable object representing the methods or instance methods
|
9
|
+
# represented by the calls to `Object#fn` or `Module#fm`.
|
10
|
+
# Did I tell you yet? It is sooooo out not be functional...
|
11
|
+
class BoundBehavior
|
12
|
+
include Behavior
|
13
|
+
attr_reader :args, :block, :method, :receiver
|
14
|
+
|
15
|
+
extend Forwarder
|
16
|
+
forward :arity, to: :method
|
17
|
+
|
18
|
+
def call *a, &b
|
19
|
+
method
|
20
|
+
.( *(a + args), &(b||block) )
|
21
|
+
end
|
22
|
+
alias_method :[], :call
|
23
|
+
|
24
|
+
def to_proc
|
25
|
+
-> *a, &b do
|
26
|
+
method
|
27
|
+
.( *(a + args), &(b||block) )
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def initialize receiver, method, *args, &block
|
33
|
+
@receiver = receiver
|
34
|
+
@method = method
|
35
|
+
@args = args
|
36
|
+
@block = block
|
37
|
+
end
|
38
|
+
|
39
|
+
end # class BoundBehavior
|
40
|
+
end # module Behavior
|
41
|
+
end # module Lab42
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
module Lab42
|
3
|
+
module Behavior
|
4
|
+
module Composer extend self
|
5
|
+
def zero_arity_composition lhs, rhs
|
6
|
+
Lab42::Behavior::ProcBehavior.new do |*args, &blk|
|
7
|
+
lhs.( *args, &blk )
|
8
|
+
rhs.()
|
9
|
+
end
|
10
|
+
end
|
11
|
+
def arg_passing_composition lhs, rhs
|
12
|
+
Lab42::Behavior::ProcBehavior.new do |*args, &blk|
|
13
|
+
rhs
|
14
|
+
.( lhs
|
15
|
+
.( *args, &blk ) )
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end # module Composer
|
19
|
+
|
20
|
+
module Composition
|
21
|
+
def | behavior
|
22
|
+
if behavior.arity.zero?
|
23
|
+
Composer.zero_arity_composition self, behavior
|
24
|
+
else
|
25
|
+
Composer.arg_passing_composition self, behavior
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end # module Composition
|
29
|
+
include Composition
|
30
|
+
end # class Behavior
|
31
|
+
end # module Lab42
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'forwarder'
|
2
|
+
module Lab42
|
3
|
+
module Behavior
|
4
|
+
class ProcBehavior
|
5
|
+
include Behavior
|
6
|
+
attr_reader :behavior
|
7
|
+
|
8
|
+
extend Forwarder
|
9
|
+
forward_all :arity, :call, :to_proc, to: :behavior
|
10
|
+
|
11
|
+
private
|
12
|
+
def initialize proc=nil, &blk
|
13
|
+
@behavior = proc || blk || ->{}
|
14
|
+
end
|
15
|
+
end # class ProcBehavior
|
16
|
+
|
17
|
+
class ::Proc
|
18
|
+
def to_behavior
|
19
|
+
Lab42::Behavior::ProcBehavior.new self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end # module Behavior
|
23
|
+
end # module Lab42
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require_relative '
|
2
|
-
require_relative '
|
1
|
+
require_relative 'unbound_behavior'
|
2
|
+
require_relative 'bound_behavior'
|
3
3
|
module Lab42
|
4
|
-
|
4
|
+
module Behavior
|
5
5
|
# Hey man really, that's all??? All my responsibility is to intercept
|
6
6
|
# missing methods and sending them off to that Lab42::Behavior bloke,
|
7
7
|
# having him have all the fun!!!! You cannott be serious by any known
|
@@ -16,9 +16,9 @@ module Lab42
|
|
16
16
|
|
17
17
|
def method_missing *args, &blk
|
18
18
|
fm ?
|
19
|
-
Lab42::UnboundBehavior.new( receiver, receiver.instance_method( args.first ), *args.drop(1), &blk ) :
|
20
|
-
Lab42::Behavior.new( receiver, receiver.method( args.first ), *args.drop(1), &blk )
|
19
|
+
Lab42::Behavior::UnboundBehavior.new( receiver, receiver.instance_method( args.first ), *args.drop(1), &blk ) :
|
20
|
+
Lab42::Behavior::BoundBehavior.new( receiver, receiver.method( args.first ), *args.drop(1), &blk )
|
21
21
|
end
|
22
22
|
end # class Proxy
|
23
|
-
end #
|
23
|
+
end # module Behavior
|
24
24
|
end # module Lab42
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Lab42
|
2
|
+
module Behavior
|
3
|
+
class SendBehavior
|
4
|
+
include Behavior
|
5
|
+
attr_reader :args, :block, :method
|
6
|
+
|
7
|
+
def arity; -1 end
|
8
|
+
|
9
|
+
def call rcv, *a, &b
|
10
|
+
rcv.send( method, *(a+args), &(b||block) )
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_proc
|
14
|
+
-> rcv, *a, &b do
|
15
|
+
rcv.send( method, *(a+args), &(b||block) )
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Rebinding:
|
20
|
+
# We still apply our LIFO policy! So much for the proverbial
|
21
|
+
# "The early bird catches the worm"? Anyway, what would I do
|
22
|
+
# with a worm??? (Mescal maybe?)
|
23
|
+
def _ *a, &b
|
24
|
+
self.class.new method, *(a + args), &(b||block)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def initialize method, *args, &block
|
29
|
+
@method = method
|
30
|
+
@args = args
|
31
|
+
@block = block
|
32
|
+
end
|
33
|
+
|
34
|
+
end # class SendBehavior
|
35
|
+
end # module Behavior
|
36
|
+
end # module Lab42
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'composition'
|
2
|
+
module Lab42
|
3
|
+
module Behavior
|
4
|
+
|
5
|
+
# Thank youn my dear Proxy, for sending me all the information
|
6
|
+
# I, the clever guy, who is having all the fun, will make best
|
7
|
+
# use of it by being an extremly, yes I said *extremly* clever
|
8
|
+
# callable object representing the methods or instance methods
|
9
|
+
# represented by the calls to `Object#fn` or `Module#fm`.
|
10
|
+
# Did I tell you yet? It is sooooo out not be functional...
|
11
|
+
class UnboundBehavior
|
12
|
+
include Behavior
|
13
|
+
attr_reader :args, :block, :method
|
14
|
+
|
15
|
+
# Increment method's arity by one as we need to bind the
|
16
|
+
# first argument to the method
|
17
|
+
def arity
|
18
|
+
method.arity.succ
|
19
|
+
end
|
20
|
+
|
21
|
+
def call *a, &b
|
22
|
+
available_args = a + args
|
23
|
+
m = method.bind available_args.first
|
24
|
+
m.( *available_args.drop(1), &(b||block) )
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_proc
|
28
|
+
-> *a, &b do
|
29
|
+
available_args = a + args
|
30
|
+
method.bind( available_args.first )
|
31
|
+
.( *available_args.drop(1), &(b||block) )
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Rebinding:
|
36
|
+
# We still apply our LIFO policy! So much for the proverbial
|
37
|
+
# "The early bird catches the worm"? Anyway, what would I do
|
38
|
+
# with a worm??? (Mescal maybe?)
|
39
|
+
def _ *a, &b
|
40
|
+
self.class.new @klass, method, *(a + args), &(b||block)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def initialize klass, method, *args, &block
|
45
|
+
@klass = klass
|
46
|
+
@method = method
|
47
|
+
@args = args
|
48
|
+
@block = block
|
49
|
+
end
|
50
|
+
|
51
|
+
end # class UnboundBehavior
|
52
|
+
end # module Behavior
|
53
|
+
end # module Lab42
|
data/lib/lab42/core/behavior.rb
CHANGED
@@ -1,38 +1,13 @@
|
|
1
1
|
require 'forwarder'
|
2
|
+
require_relative 'behavior/composition'
|
3
|
+
require_relative 'behavior/negation'
|
4
|
+
require_relative 'behavior/proc_behavior'
|
5
|
+
require_relative 'behavior/proxy'
|
6
|
+
require_relative 'behavior/send_behavior'
|
7
|
+
require_relative 'behavior/bound_behavior'
|
8
|
+
require_relative 'behavior/unbound_behavior'
|
2
9
|
|
3
10
|
module Lab42
|
4
|
-
|
5
|
-
#
|
6
|
-
# use of it by being an extremly, yes I said *extremly* clever
|
7
|
-
# callable object representing the methods or instance methods
|
8
|
-
# represented by the calls to `Object#fn` or `Module#fm`.
|
9
|
-
# Did I tell you yet? It is sooooo out not be functional...
|
10
|
-
class Behavior
|
11
|
-
attr_reader :args, :block, :method, :receiver
|
12
|
-
|
13
|
-
|
14
|
-
def call *a, &b
|
15
|
-
method
|
16
|
-
.( *(a + args), &(b||block) )
|
17
|
-
end
|
18
|
-
alias_method :[], :call
|
19
|
-
|
20
|
-
def to_proc
|
21
|
-
-> *a, &b do
|
22
|
-
method
|
23
|
-
.( *(a + args), &(b||block) )
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
private
|
29
|
-
def initialize receiver, method, *args, &block
|
30
|
-
@receiver = receiver
|
31
|
-
@method = method
|
32
|
-
@args = args
|
33
|
-
@block = block
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
end # class Behavior
|
11
|
+
module Behavior
|
12
|
+
end # module Behavior
|
38
13
|
end # module Lab42
|
data/lib/lab42/core/dir.rb
CHANGED
@@ -2,21 +2,21 @@ require_relative 'meta'
|
|
2
2
|
class << Dir
|
3
3
|
def abs_files glob_para, *rst, &blk
|
4
4
|
glob_para = File.join( *glob_para ) if Array === glob_para
|
5
|
-
blk = Lab42::Meta::Behavior *rst, &blk
|
5
|
+
blk = Lab42::Meta::Behavior.behavior *rst, &blk
|
6
6
|
|
7
7
|
__files__ :last, glob_para, &blk
|
8
8
|
end
|
9
9
|
|
10
10
|
def files glob_para, *rst, &blk
|
11
11
|
glob_para = File.join( *glob_para ) if Array === glob_para
|
12
|
-
blk = Lab42::Meta::Behavior *rst, &blk
|
12
|
+
blk = Lab42::Meta::Behavior.behavior *rst, &blk
|
13
13
|
|
14
14
|
__files__ :both, glob_para, &blk
|
15
15
|
end
|
16
16
|
|
17
17
|
def rel_files glob_para, *rst, &blk
|
18
18
|
glob_para = File.join( *glob_para ) if Array === glob_para
|
19
|
-
blk = Lab42::Meta::Behavior *rst, &blk
|
19
|
+
blk = Lab42::Meta::Behavior.behavior *rst, &blk
|
20
20
|
|
21
21
|
__files__ :first, glob_para, &blk
|
22
22
|
end
|
data/lib/lab42/core/fn.rb
CHANGED
data/lib/lab42/core/hash.rb
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
require_relative 'meta'
|
2
2
|
class Hash
|
3
3
|
|
4
|
+
def fetch! key, *defaults, &defblk
|
5
|
+
default_present = !(defaults.empty? && defblk.nil?)
|
6
|
+
return fetch key unless default_present
|
7
|
+
fetch key do
|
8
|
+
self[ key ] = defblk ? defblk.() : defaults.first
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def replace_rec *keys, limit: nil, limits: nil, &valblock
|
13
|
+
raise ArgumentError, "must not pass in limit: and limits: keyword parameters" if limit && limits
|
14
|
+
return Lab42::Meta::Hash.hash_replace_rec self, keys, valblock, limit || limits
|
15
|
+
end
|
16
|
+
|
4
17
|
def only *args
|
5
18
|
args.inject Hash.new do | r, k |
|
6
19
|
if has_key? k
|
@@ -12,12 +25,12 @@ class Hash
|
|
12
25
|
end
|
13
26
|
|
14
27
|
def reject_values *behavior, &beh
|
15
|
-
beh = Lab42::Meta::Behavior *behavior, &beh
|
28
|
+
beh = Lab42::Meta::Behavior.behavior *behavior, &beh
|
16
29
|
reject{ |_, v| beh.(v) }
|
17
30
|
end
|
18
31
|
|
19
32
|
def select_values *behavior, &beh
|
20
|
-
beh = Lab42::Meta::Behavior *behavior, &beh
|
33
|
+
beh = Lab42::Meta::Behavior.behavior *behavior, &beh
|
21
34
|
select{ |_, v| beh.(v) }
|
22
35
|
end
|
23
36
|
|
@@ -38,12 +51,4 @@ class Hash
|
|
38
51
|
end
|
39
52
|
end
|
40
53
|
end
|
41
|
-
|
42
|
-
def fetch! key, *defaults, &defblk
|
43
|
-
default_present = !(defaults.empty? && defblk.nil?)
|
44
|
-
return fetch key unless default_present
|
45
|
-
fetch key do
|
46
|
-
self[ key ] = defblk ? defblk.() : defaults.first
|
47
|
-
end
|
48
|
-
end
|
49
54
|
end # class Hash
|
data/lib/lab42/core/kernel.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Kernel
|
2
|
+
def require_relative_dir &blk
|
3
|
+
raise ArgumentError, 'need a block to determine source location' unless blk
|
4
|
+
dir = File.expand_path File.join( '..', blk.(), '*.rb'), blk.source_location.first
|
5
|
+
Dir.glob( dir ).each do | file |
|
6
|
+
require file
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
include Kernel
|
@@ -1,38 +1,43 @@
|
|
1
1
|
require_relative 'hash'
|
2
2
|
|
3
|
-
module Lab42::
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module Lab42::Memoizer extend self
|
4
|
+
def make_ivar_name from_sym
|
5
|
+
[
|
6
|
+
'@',
|
7
|
+
from_sym
|
8
|
+
.to_s
|
9
|
+
.sub('!', 'bang')
|
10
|
+
.sub('?', '_p'),
|
11
|
+
Time.now.nsec.to_s(36),
|
12
|
+
SecureRandom.uuid.gsub('-','')
|
13
|
+
].join("_")
|
9
14
|
end
|
10
|
-
|
15
|
+
|
16
|
+
end # module Lab42::Memoizer
|
11
17
|
|
12
18
|
class Module
|
13
19
|
|
14
|
-
include Lab42::Unmemoizer
|
15
|
-
|
16
20
|
def lazy_attr sym, &blk
|
17
21
|
raise ArgumentError, 'missing initialization block' unless blk
|
18
|
-
|
19
|
-
ivar_name = "@__#{sym}__"
|
20
|
-
return instance_variable_get( ivar_name ) if instance_variable_defined? ivar_name
|
21
|
-
instance_variable_set ivar_name, instance_eval( &blk )
|
22
|
-
end
|
22
|
+
memo sym, &blk
|
23
23
|
end
|
24
24
|
|
25
25
|
def memoize sym
|
26
|
-
include Lab42::Unmemoizer
|
27
26
|
orig_method = instance_method sym
|
27
|
+
ivar_name = Lab42::Memoizer.make_ivar_name sym
|
28
|
+
|
28
29
|
define_method sym do |*args|
|
29
|
-
ivar_name = "@__#{sym}__"
|
30
30
|
instance_variable_set ivar_name, {} unless instance_variable_defined? ivar_name
|
31
31
|
instance_variable_get( ivar_name ).fetch! args do
|
32
|
-
# Not cached yet
|
32
|
+
# Not cached yet, caching by means of fetch!
|
33
33
|
orig_method.bind( self ).( *args )
|
34
34
|
end
|
35
35
|
end
|
36
|
+
|
37
|
+
define_method "unmemoize_memo_#{sym}" do | *args |
|
38
|
+
return instance_variable_set ivar_name, {} if args.empty?
|
39
|
+
instance_variable_get( ivar_name ).delete args
|
40
|
+
end
|
36
41
|
end
|
37
42
|
|
38
43
|
def memo *args, &blk
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Lab42
|
2
|
+
module Meta
|
3
|
+
module Behavior extend self
|
4
|
+
def behavior *args, &blk
|
5
|
+
return blk if blk
|
6
|
+
determine_behavior_from args
|
7
|
+
end
|
8
|
+
|
9
|
+
def call_with_arity blk, params, base_arity: 1
|
10
|
+
return blk.(*params.first(base_arity)) if blk.arity < 0
|
11
|
+
blk.(*params.first(blk.arity))
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def determine_behavior_from args
|
16
|
+
return make_callable args.last if args.last && args.last.respond_to?( :call )
|
17
|
+
return make_message_sender args if Symbol === args.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def make_callable callable
|
21
|
+
return callable if Proc === callable
|
22
|
+
-> *a, &b do
|
23
|
+
callable.(*a, &b)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_message_sender args
|
28
|
+
-> (rcv, *late_args) do
|
29
|
+
rcv.send( args.first, *( late_args + args.drop(1) ) )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end # module Behavior
|
33
|
+
end # module Meta
|
34
|
+
end # module Lab42
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Lab42
|
2
|
+
module Meta
|
3
|
+
module Hash extend self
|
4
|
+
def hash_replace_rec orig, keys, valblock, limits
|
5
|
+
return unlimited_hash_replace_rec orig, keys, valblock unless limits
|
6
|
+
limits = ::Hash[ *keys.zip( [limits] * keys.size ).flatten ] unless ::Hash === limits
|
7
|
+
limited_hash_replace_rec orig, keys, valblock, limits
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def limited_hash_replace_rec orig, keys, valblock, limits
|
12
|
+
orig.inject ::Hash.new do | h, (k, v) |
|
13
|
+
h.merge! k => limited_value( keys, k, v, valblock, limits )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def limited_value keys, k, v, valblock, limits
|
18
|
+
if keys.include?( k ) && limits.fetch(k, 1) > 0
|
19
|
+
limits[k] and limits[k] -= 1
|
20
|
+
Behavior.call_with_arity valblock, [v, k]
|
21
|
+
else
|
22
|
+
recur_or_value keys, v, valblock, limits
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def recur_or_value keys, v, valblock, limits
|
27
|
+
if ::Hash === v
|
28
|
+
limited_hash_replace_rec v, keys, valblock, limits
|
29
|
+
else
|
30
|
+
v
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def unlimited_hash_replace_rec orig, keys, valblock
|
35
|
+
orig.inject ::Hash.new do | h, (k, v) |
|
36
|
+
h.merge! k => unlimited_value( keys, k, v, valblock )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
def unlimited_value keys, k, v, valblock
|
40
|
+
if keys.include? k
|
41
|
+
Behavior.call_with_arity valblock, [v, k]
|
42
|
+
elsif ::Hash === v
|
43
|
+
unlimited_hash_replace_rec v, keys, valblock
|
44
|
+
else
|
45
|
+
v
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end # module Hash
|
49
|
+
end # module Meta
|
50
|
+
end # module Lab42
|
data/lib/lab42/core/meta.rb
CHANGED
@@ -1,27 +1 @@
|
|
1
|
-
|
2
|
-
module Meta extend self
|
3
|
-
def Behavior *args, &blk
|
4
|
-
return blk if blk
|
5
|
-
determine_behavior_from args
|
6
|
-
end
|
7
|
-
|
8
|
-
private
|
9
|
-
def determine_behavior_from args
|
10
|
-
return make_callable args.last if args.last && args.last.respond_to?( :call )
|
11
|
-
return make_message_sender args if Symbol === args.first
|
12
|
-
end
|
13
|
-
|
14
|
-
def make_callable callable
|
15
|
-
return callable if Proc === callable
|
16
|
-
-> *a, &b do
|
17
|
-
callable.(*a, &b)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def make_message_sender args
|
22
|
-
-> (rcv, *late_args) do
|
23
|
-
rcv.send( args.first, *( late_args + args.drop(1) ) )
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end # module Meta
|
27
|
-
end # module Lab42
|
1
|
+
require_relative_dir{ 'meta' }
|
@@ -42,6 +42,14 @@ class OpenObject
|
|
42
42
|
def inherited *args, **kwds, &blk
|
43
43
|
raise RuntimeError, "I prefer delegation to inheritance, if you do not, MP me"
|
44
44
|
end
|
45
|
+
|
46
|
+
def merging *args
|
47
|
+
new **(
|
48
|
+
args.inject Hash.new do |r, arg|
|
49
|
+
r.merge arg.to_hash
|
50
|
+
end
|
51
|
+
)
|
52
|
+
end
|
45
53
|
end
|
46
54
|
end # class OpenObject
|
47
55
|
|
data/lib/lab42/core/version.rb
CHANGED
data/lib/lab42/core.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lab42_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.4'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Dober
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: forwarder2
|
@@ -120,9 +120,14 @@ files:
|
|
120
120
|
- lib/lab42/core.rb
|
121
121
|
- lib/lab42/core/array.rb
|
122
122
|
- lib/lab42/core/b.rb
|
123
|
-
- lib/lab42/core/behave.rb
|
124
123
|
- lib/lab42/core/behavior.rb
|
124
|
+
- lib/lab42/core/behavior/bound_behavior.rb
|
125
|
+
- lib/lab42/core/behavior/composition.rb
|
126
|
+
- lib/lab42/core/behavior/negation.rb
|
127
|
+
- lib/lab42/core/behavior/proc_behavior.rb
|
125
128
|
- lib/lab42/core/behavior/proxy.rb
|
129
|
+
- lib/lab42/core/behavior/send_behavior.rb
|
130
|
+
- lib/lab42/core/behavior/unbound_behavior.rb
|
126
131
|
- lib/lab42/core/console_tools.rb
|
127
132
|
- lib/lab42/core/console_tools/enumerable.rb
|
128
133
|
- lib/lab42/core/console_tools/func.rb
|
@@ -134,9 +139,10 @@ files:
|
|
134
139
|
- lib/lab42/core/kernel.rb
|
135
140
|
- lib/lab42/core/memoization.rb
|
136
141
|
- lib/lab42/core/meta.rb
|
142
|
+
- lib/lab42/core/meta/behavior.rb
|
143
|
+
- lib/lab42/core/meta/hash.rb
|
137
144
|
- lib/lab42/core/old_ruby2.rb
|
138
145
|
- lib/lab42/core/open_object.rb
|
139
|
-
- lib/lab42/core/unbound_behavior.rb
|
140
146
|
- lib/lab42/core/version.rb
|
141
147
|
- lib/lab42/file.rb
|
142
148
|
- lib/lab42/lazy.rb
|
@@ -160,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
166
|
version: '0'
|
161
167
|
requirements: []
|
162
168
|
rubyforge_project:
|
163
|
-
rubygems_version: 2.4.
|
169
|
+
rubygems_version: 2.4.8
|
164
170
|
signing_key:
|
165
171
|
specification_version: 4
|
166
172
|
summary: Simple Ruby Core Module Extensions (for more see lab42_more)
|
data/lib/lab42/core/behave.rb
DELETED
File without changes
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require_relative 'behavior'
|
2
|
-
|
3
|
-
module Lab42
|
4
|
-
# Thank youn my dear Proxy, for sending me all the information
|
5
|
-
# I, the clever guy, who is having all the fun, will make best
|
6
|
-
# use of it by being an extremly, yes I said *extremly* clever
|
7
|
-
# callable object representing the methods or instance methods
|
8
|
-
# represented by the calls to `Object#fn` or `Module#fm`.
|
9
|
-
# Did I tell you yet? It is sooooo out not be functional...
|
10
|
-
class UnboundBehavior
|
11
|
-
attr_reader :args, :block, :method
|
12
|
-
|
13
|
-
def call *a, &b
|
14
|
-
available_args = a + args
|
15
|
-
m = method.bind available_args.first
|
16
|
-
m.( *available_args.drop(1), &(b||block) )
|
17
|
-
end
|
18
|
-
|
19
|
-
def to_proc
|
20
|
-
-> *a, &b do
|
21
|
-
available_args = a + args
|
22
|
-
method.bind( available_args.first )
|
23
|
-
.( *available_args.drop(1), &(b||block) )
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# Rebinding:
|
28
|
-
# We still apply our LIFO policy! So much for the proverbial
|
29
|
-
# "The early bird catches the worm"? Anyway, what would I do
|
30
|
-
# with a worm??? (Mescal maybe?)
|
31
|
-
def _ *a, &b
|
32
|
-
self.class.new @klass, method, *(a + args), &(b||block)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
def initialize klass, method, *args, &block
|
37
|
-
@klass = klass
|
38
|
-
@method = method
|
39
|
-
@args = args
|
40
|
-
@block = block
|
41
|
-
end
|
42
|
-
|
43
|
-
end # class Behavior
|
44
|
-
end # module Lab42
|