fn_space 0.1.0 → 1.0.0

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 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: []