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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 811602e26a532105f37e6c56e20b81c60c6c9440
4
- data.tar.gz: a49df20d40c2c6260ef58f66e9c0ed7a6b446a68
3
+ metadata.gz: ef2eda95f4d90d23f7159493efab4a5d2e27443c
4
+ data.tar.gz: f14a79bff5994467498973e2470b6a770ca952cc
5
5
  SHA512:
6
- metadata.gz: 79be1355ea6761017771e5c9f1b7a9e3b8b99fdc221113af0df860063781bf856324b80b873b78359e8b049a982c6e7327c33c7186c39aadd532cc50ac2b036e
7
- data.tar.gz: 239e101d091b49c410e31c1fc83c0a5c80b916bb78c2f701fca24b262c5357ce6d0d8533d91ba2a1b606c47e190d117f127f7d90a05681854483b640548b4bfa
6
+ metadata.gz: d28c17beb0190f6e029dc9ec2434659cddd3658d0345d3c468535b320ed62ad004ce67955b442dea5e675c70f58fd61f1da92bc544b212572c0acfbd980e17be
7
+ data.tar.gz: d92fd1d315563e6093b9a7982e71157069bb34f4c1479d1181c794f3e3d6f92aa6ac5d3d9f50ef453962d4a2185539203f5f09f8befd57796d6865b5bb9d7c01
data/README.md CHANGED
@@ -1,36 +1,147 @@
1
1
  # FnSpace
2
2
 
3
- A Ruby class for explicit function importing and exporting.
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
- module Foo
11
- def self.add(a, b)
12
- a + b
13
- end
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
- def self.take(a, b)
16
- a - b
17
- end
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
- Bar = {
21
- times: ->(a, b) { a * b }
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
- class FnSpace
25
- add, take = import(:add, :take).from 'Foo'
26
- times = import(:times).from 'Bar'
121
+ ``` ruby
122
+ fn_space do |import|
123
+ chain = import.(:chain).from FnSpace::Utils
27
124
 
28
- result = ->(a, b) { add.(times.(a, b), take.(a, b)) }
125
+ double = ->(v) { v * 2 }
126
+ log = ->(v) { puts v }
29
127
 
30
- export(result: result).to 'Sums'
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
- Sums[:result].(5, 8) # 37
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
- class FnSpace < BasicObject
2
- def self.import(*names)
3
- Importer.new(names)
4
- end
5
-
6
- def self.export(obj)
7
- Exporter.new(obj)
8
- end
9
-
10
- class Importer
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,8 @@
1
+ module FnSpace
2
+ module Assignable
3
+ def assign(name, &b)
4
+ define_singleton_method(name, &b)
5
+ self
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ FnSpace::Export = ->(const, obj) do
2
+ parent, _, child = const.to_s.rpartition('::')
3
+ parent = parent.empty? ? Object : Object.const_get(parent)
4
+ parent.const_set(child, obj)
5
+ 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: 0.1.0
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-28 00:00:00.000000000 Z
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 function importing and exporting
69
+ summary: A Ruby class for explicit importing and exporting
46
70
  test_files: []