fn_space 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +128 -17
- data/lib/fn_space.rb +10 -36
- data/lib/fn_space/assignable.rb +8 -0
- data/lib/fn_space/export.rb +5 -0
- data/lib/fn_space/import.rb +21 -0
- data/lib/fn_space/utils.rb +15 -0
- metadata +28 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef2eda95f4d90d23f7159493efab4a5d2e27443c
|
4
|
+
data.tar.gz: f14a79bff5994467498973e2470b6a770ca952cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d28c17beb0190f6e029dc9ec2434659cddd3658d0345d3c468535b320ed62ad004ce67955b442dea5e675c70f58fd61f1da92bc544b212572c0acfbd980e17be
|
7
|
+
data.tar.gz: d92fd1d315563e6093b9a7982e71157069bb34f4c1479d1181c794f3e3d6f92aa6ac5d3d9f50ef453962d4a2185539203f5f09f8befd57796d6865b5bb9d7c01
|
data/README.md
CHANGED
@@ -1,36 +1,147 @@
|
|
1
1
|
# FnSpace
|
2
2
|
|
3
|
-
|
3
|
+
FnSpace is a space where functions can be treated as first class objects. It
|
4
|
+
provides import and export helpers that prioritize functions and utility
|
5
|
+
methods to enable functional paradigms.
|
4
6
|
|
5
7
|
## Example
|
6
8
|
|
7
9
|
``` ruby
|
10
|
+
# my_awsome_project/formula.rb
|
8
11
|
require 'fn_space'
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
fn_space(:Formula) do |import, exports|
|
14
|
+
pi = 3.14
|
15
|
+
exports.circ = ->(r) { 2 * pi * r }
|
16
|
+
exports.area = ->(r) { pi * r ** 2 }
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
``` ruby
|
21
|
+
# my_awsome_project/other_file.rb
|
22
|
+
require 'fn_space'
|
23
|
+
require_relative 'formula'
|
24
|
+
|
25
|
+
fn_space do |import|
|
26
|
+
fn1, fn2 = import.(:area, :circ).from Formula
|
27
|
+
fn1.(8) # 200.96
|
28
|
+
fn2.(8) # 50.24
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
### `fn_space(const = nil) { |import, exports| block }`
|
35
|
+
|
36
|
+
`fn_space` is a global method that executes a block passed to it in an
|
37
|
+
anonymous module. It passes two arguments to the provided block, `import` and
|
38
|
+
`exports`.
|
39
|
+
|
40
|
+
It optionally takes a new constant's name as it first argument, which will then
|
41
|
+
be used to store any properties added to the `exports` OpenStruct.
|
42
|
+
|
43
|
+
### `import.(*names).from Source`
|
44
|
+
|
45
|
+
`import.()` can be used to import properties from a source. If only a single
|
46
|
+
property is requested then only a single value will be return, otherwise an
|
47
|
+
array will be.
|
48
|
+
|
49
|
+
``` ruby
|
50
|
+
MagicNumbers = Struct.new(:a, :b, :c).new(5, 7, 19)
|
51
|
+
|
52
|
+
fn_space do |import|
|
53
|
+
b = import.(:b).from MagicNumbers
|
54
|
+
c, a = import.(:c, :a).from MagicNumbers
|
55
|
+
|
56
|
+
a + b + c # 31
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
### `import.methods.(*names).from Source`
|
61
|
+
|
62
|
+
`import.methods.()` can be used to import methods from a source as method objects.
|
63
|
+
|
64
|
+
``` ruby
|
65
|
+
fn_space do |import|
|
66
|
+
tan = import.methods.(:tan).from Math
|
67
|
+
sin, cos = import.methods.(:sin, :cos).from Math
|
68
|
+
pi = Math::PI
|
14
69
|
|
15
|
-
|
16
|
-
|
17
|
-
|
70
|
+
tan.(0) # 0
|
71
|
+
sin.(pi/2) # 1.0
|
72
|
+
cos.(pi) # -1.0
|
18
73
|
end
|
74
|
+
```
|
75
|
+
|
76
|
+
## Utils
|
77
|
+
|
78
|
+
### `mod.()`
|
79
|
+
|
80
|
+
`mod.()` creates a new anonymous module with an `assign` singleton method that
|
81
|
+
can be used to create singleton methods in a chain.
|
82
|
+
|
83
|
+
``` ruby
|
84
|
+
fn_space do |import|
|
85
|
+
mod = import.(:mod).from FnSpace::Utils
|
86
|
+
foo = mod.()
|
87
|
+
.assign(:add) { |a, b| a + b }
|
88
|
+
.assign(:take) { |a, b| a - b }
|
89
|
+
|
90
|
+
foo.add(3, 4) # 7
|
91
|
+
foo.take(5, 2) # 3
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
### `struct.(hash)`
|
96
|
+
|
97
|
+
`struct.()` takes a hash and creates a new anonymous module with properties
|
98
|
+
taken from the hash.
|
99
|
+
|
100
|
+
``` ruby
|
101
|
+
fn_space do |import|
|
102
|
+
struct = import.(:struct).from FnSpace::Utils
|
103
|
+
crds = struct.(x: 0.5, y: 1.5, z: -1.0)
|
104
|
+
crds.x + crds.y + crds.z # 1.0
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
### `chain.(value)`
|
109
|
+
|
110
|
+
`chain.()` wraps around a value and can be used to chain functions to be applied
|
111
|
+
to the value. It does this by providing the following methods:
|
112
|
+
|
113
|
+
* `>>` - Applies a function to the value and replaces the value with the result.
|
114
|
+
* `<<` - Applies a function to the value but does not replace the value.
|
115
|
+
* `|` - Applies a function to the chain object itself.
|
116
|
+
* `value` - Returns the value.
|
19
117
|
|
20
|
-
|
21
|
-
|
22
|
-
}
|
118
|
+
Function arguments have their `#to_proc` method called first such that symbols
|
119
|
+
can be used to call methods on an object.
|
23
120
|
|
24
|
-
|
25
|
-
|
26
|
-
|
121
|
+
``` ruby
|
122
|
+
fn_space do |import|
|
123
|
+
chain = import.(:chain).from FnSpace::Utils
|
27
124
|
|
28
|
-
|
125
|
+
double = ->(v) { v * 2 }
|
126
|
+
log = ->(v) { puts v }
|
29
127
|
|
30
|
-
|
128
|
+
res = chain.(3) >> double >> :next << log >> double << log >> :next | :value
|
129
|
+
# 7
|
130
|
+
# 14
|
131
|
+
puts res # 15
|
31
132
|
end
|
133
|
+
```
|
134
|
+
|
135
|
+
### `apply_send.(*args)`
|
32
136
|
|
33
|
-
|
137
|
+
`apply_send.()` can be used to apply arguments to an object's `send` method.
|
138
|
+
This can useful used in conjunction with the `chain` utility.
|
139
|
+
|
140
|
+
``` ruby
|
141
|
+
fn_space do |import|
|
142
|
+
chain, send = import.(:chain, :apply_send).from FnSpace::Utils
|
143
|
+
chain.(2) >> send.(:**, 3) >> send.(:/, 4) | :value # 2
|
144
|
+
end
|
34
145
|
```
|
35
146
|
|
36
147
|
## Installation
|
data/lib/fn_space.rb
CHANGED
@@ -1,36 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(names)
|
12
|
-
@names = names
|
13
|
-
end
|
14
|
-
|
15
|
-
def from(constant)
|
16
|
-
obj = ::Object.const_get(constant)
|
17
|
-
is_hash = obj.respond_to?(:has_key?)
|
18
|
-
functions = @names.map { |m| is_hash ? obj[m].to_proc : obj.method(m) }
|
19
|
-
functions.length == 1 ? functions.first : functions
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Exporter
|
24
|
-
def initialize(obj)
|
25
|
-
@obj = obj
|
26
|
-
end
|
27
|
-
|
28
|
-
def to(constant)
|
29
|
-
if ::Object.const_defined?(constant)
|
30
|
-
::Object.const_get(constant).merge!(@functions)
|
31
|
-
else
|
32
|
-
::Object.const_set(constant, @functions)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
1
|
+
require 'ostruct'
|
2
|
+
require_relative 'fn_space/utils'
|
3
|
+
require_relative 'fn_space/import'
|
4
|
+
require_relative 'fn_space/export'
|
5
|
+
|
6
|
+
def fn_space(const = nil, &b)
|
7
|
+
exports = OpenStruct.new
|
8
|
+
Module.new.instance_exec(FnSpace::Import, exports, &b)
|
9
|
+
FnSpace::Export.(const, FnSpace::Utils.struct.(exports.to_h)) if const
|
10
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'utils'
|
2
|
+
chain = FnSpace::Utils.chain
|
3
|
+
mod = FnSpace::Utils.mod
|
4
|
+
|
5
|
+
first_or_all = ->(array) { array.length == 1 ? array.first : array }
|
6
|
+
map = ->(array) { ->(map_fn) { array.map(&map_fn) } }
|
7
|
+
send_map_fn = ->(obj) { ->(name) { obj.send(name) } }
|
8
|
+
method_map_fn = ->(obj) { ->(name) { obj.method(name) } }
|
9
|
+
|
10
|
+
importer = ->(names, map_fn) do
|
11
|
+
mod.().assign(:from) do |source|
|
12
|
+
chain.(source) >> map_fn >> map.(names) >> first_or_all | :value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
import = ->(*names) { importer.(names, send_map_fn) }
|
17
|
+
import_methods = ->(*names) { importer.(names, method_map_fn) }
|
18
|
+
|
19
|
+
FnSpace::Import = mod.()
|
20
|
+
.assign(:call, &import)
|
21
|
+
.assign(:methods){import_methods}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'assignable'
|
2
|
+
|
3
|
+
mod = ->(&b) { Module.new(&b).extend(FnSpace::Assignable) }
|
4
|
+
struct = ->(hash) { hash.reduce(mod.()) { |obj, (k, v)| obj.assign(k){v} } }
|
5
|
+
apply_send = ->(method, *args) { ->(obj) { obj.send(method, *args) } }
|
6
|
+
|
7
|
+
chain = ->(value) do
|
8
|
+
monad = mod.()
|
9
|
+
.assign(:>>) { |fn| value = fn.to_proc.(value); monad }
|
10
|
+
.assign(:<<) { |fn| fn.to_proc.(value); monad }
|
11
|
+
.assign(:|) { |fn| fn.to_proc.(monad) }
|
12
|
+
.assign(:value) { value }
|
13
|
+
end
|
14
|
+
|
15
|
+
FnSpace::Utils = struct.(mod: mod, struct: struct, apply_send: apply_send, chain: chain)
|
metadata
CHANGED
@@ -1,15 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fn_space
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max White
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
12
|
-
dependencies:
|
11
|
+
date: 2015-10-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.1.0
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.1'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.1.0
|
13
33
|
description:
|
14
34
|
email: mushishi78@gmail.com
|
15
35
|
executables: []
|
@@ -19,6 +39,10 @@ files:
|
|
19
39
|
- LICENSE.txt
|
20
40
|
- README.md
|
21
41
|
- lib/fn_space.rb
|
42
|
+
- lib/fn_space/assignable.rb
|
43
|
+
- lib/fn_space/export.rb
|
44
|
+
- lib/fn_space/import.rb
|
45
|
+
- lib/fn_space/utils.rb
|
22
46
|
homepage: https://github.com/mushishi78/fn_space
|
23
47
|
licenses:
|
24
48
|
- MIT
|
@@ -42,5 +66,5 @@ rubyforge_project:
|
|
42
66
|
rubygems_version: 2.4.8
|
43
67
|
signing_key:
|
44
68
|
specification_version: 4
|
45
|
-
summary: A Ruby class for explicit
|
69
|
+
summary: A Ruby class for explicit importing and exporting
|
46
70
|
test_files: []
|