lab42_core 0.3.3 → 0.4
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.
- 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
|