funcml-core 0.9.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 229952b1c47eb4c17e0cc4209f1e0226306010425713c4d1ed9d1b6a4bd0adfb
4
+ data.tar.gz: 7435707d489decc839bad4c3697c72534fdc7fa465b44049c9e52bd4a1899e47
5
+ SHA512:
6
+ metadata.gz: 68458c9df2ec863e3030c35b082405e39c71dba66576f33f5306f0046aedd674eae5720e491ad331880f7e89e04eded00e6fc9d77b51db6af86ea8f678a2be4d
7
+ data.tar.gz: '08d321d32f188aad017170d3df8c8c42b45b3ad40939a3ec20294464679ecee0b8875bfde73f496ff7bac543fb6c536c1c327c24bcbeeebdfa92aa925525c6c2'
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Mimopotato
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # funcml-core
2
+
3
+ Funcml-core extends the standard Ruby classes (String, Integer, Hash, Array, etc.) to provide a framework for data structures. This framework makes it possible to perform mutations on data structures and is at the heart of the funcml-cli project.
4
+
5
+ Connected to funcml-cli, funcml-core can ingest JSON and YAML files and apply prepared mutations. Funcml-cli is part of a wider project, Karist, which aims to simplify the management of Kubernetes manifests using YAML.
6
+
7
+ However, funcml-core can be used in just about any project thanks to its super-simple, documented AP
8
+
9
+ ## Installation
10
+
11
+ Ruby superior to >=2.7 is required due to pattern-matching usage.
12
+
13
+ ```bash
14
+ gem install funcml-core
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ Data structures are mutated using the #mutate function, which is loaded with the funcml-core library. It is then possible to launch a mutation on any object by specifying the mutation functions as arguments to the #mutate method.
20
+
21
+ ```ruby
22
+ require "funcml-core"
23
+
24
+ simple_hash = {key: "$value"}
25
+ simple_hash.mutate(value: ["a", "great", "example"])
26
+
27
+ # { key: ["a", "great", "example"] }
28
+ ```
29
+
30
+ Many mutations are supported. Funcml-core includes:
31
+
32
+ * variables support
33
+ * Time functions
34
+ * Mathematics
35
+ * Hash/dictionaries manipulations
36
+ * Cryptography (encryption/decryption with AES)
37
+ * Encoding (base64, SHA1, SHA256, MD5...)
38
+ * External files inclusion
39
+ * Arrays/lists manipulations
40
+ * And many others !
41
+
42
+ Read the doc at [Funcml.org](https://funcml.org) to learn more about what funcml-core supports.
43
+
44
+ ## How it works ?
45
+
46
+ A #mutate method is implemented for each Ruby object. This method recursively applies the various mutations specified as arguments to the first call.
47
+
48
+ Funcml-core exposes mutation functions in two ways: either through additional hash keys, determined by the prefix "_", or through strings beginning with "$".
49
+
50
+ ```ruby
51
+ struct = {
52
+ mutations: {
53
+ first: "hello",
54
+ second: "world",
55
+ third: "!"
56
+ },
57
+ key: {
58
+ value: {
59
+ _if: [
60
+ {eq: [{_last: '$mutations'}, "!"]}
61
+ ],
62
+ _concat: {
63
+ items: [
64
+ '$mutations.first',
65
+ '$mutations.second',
66
+ '$mutations.third'
67
+ ],
68
+ sep: " "
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ struct[:key].mutate(struct)
75
+ # {value: "hello world !"}
76
+ ```
77
+
78
+ The implementation of funcml-core is somewhat similar in idea to LISP and you will no doubt be able to find some similarities.
79
+
80
+ The functions are applied recursively: when _concat is called, all items are first mutated before _concat's own evaluation. This is relatively similar to LISP languages where "inside the code is the first part executed".
81
+
82
+ ## Development
83
+
84
+ All functions are tested using original Ruby data structures. Take a look in the test folder to see all the funcml-core possibilities.
85
+
86
+
87
+ You can run the tests with the following command (test-unit).
88
+
89
+ ```
90
+ TESTOPTS="-v" rake test
91
+ ```
92
+
93
+ Funcml-core only extends Ruby's native classes. Under no circumstances does funcml-core handle marshal, unmarshal or file read/write operations (see funcml-cli for these parts).
94
+
95
+ ## Contributing
96
+
97
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mimopotato/funcml-core.
98
+
99
+ ## License
100
+
101
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ task default: %i[test standard]
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ def mutate(mutations)
5
+ self.map do |el|
6
+ el.mutate(mutations)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FalseClass
4
+ def mutate(_)
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Float
4
+ def mutate(_)
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ def _string(mutations)
5
+ self.fetch(:_string).then do |obj|
6
+ obj.mutate(mutations).to_s
7
+ end
8
+ end
9
+
10
+ def _int(mutations)
11
+ self.fetch(:_int).then do |obj|
12
+ obj.mutate(mutations).to_i
13
+ end
14
+ end
15
+
16
+ def _float(mutations)
17
+ self.fetch(:_float).then do |obj|
18
+ obj.mutate(mutations).to_f
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ require "digest"
3
+ require "openssl"
4
+
5
+ class Hash
6
+ include Funcml
7
+
8
+ def _sha1sum(mutations)
9
+ self.fetch(:_sha1sum).then do |value|
10
+ return Digest::SHA1.hexdigest(value.mutate(mutations))
11
+ end
12
+ end
13
+
14
+ def _sha256sum(mutations)
15
+ self.fetch(:_sha256sum).then do |value|
16
+ return Digest::SHA256.hexdigest(value.mutate(mutations))
17
+ end
18
+ end
19
+
20
+ # source https://gist.github.com/wteuber/5318013
21
+ def _encryptAES(mutations)
22
+ self.fetch(:_encryptAES).then do |blk|
23
+ case blk
24
+ in {data: data, encryptionKey: encryption_key}
25
+ cipher = OpenSSL::Cipher.new("aes-256-cbc").encrypt
26
+ cipher.key = Digest::MD5.hexdigest(encryption_key.mutate(mutations))
27
+ s = cipher.update(data.mutate(mutations)) + cipher.final
28
+ s.unpack('H*')[0].upcase
29
+ else
30
+ raise MissingEncryptionKeyException, "encryptionKey field missing in #{self.to_s}"
31
+ end
32
+ end
33
+ end
34
+
35
+ # source https://gist.github.com/wteuber/5318013
36
+ def _decryptAES(mutations)
37
+ self.fetch(:_decryptAES).then do |blk|
38
+ case blk
39
+ in {data: data, encryptionKey: encryption_key}
40
+ cipher = OpenSSL::Cipher.new("aes-256-cbc").decrypt
41
+ cipher.key = Digest::MD5.hexdigest(encryption_key.mutate(mutations))
42
+ s = [data.mutate(mutations)].pack('H*').unpack('C*').pack('c*')
43
+ cipher.update(s) + cipher.final
44
+ else
45
+ raise MissingEncryptionKeyException, "encryptionKey field missing in #{self.to_s}"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ def _keys(mutations)
5
+ self.fetch(:_keys).mutate(mutations).then do |elems|
6
+ return elems.map do |elem|
7
+ if elem.is_a?(Hash)
8
+ elem.keys
9
+ else
10
+ elem
11
+ end
12
+ end.flatten
13
+ end
14
+ end
15
+
16
+ def _values(mutations)
17
+ self.fetch(:_values).mutate(mutations).then do |elems|
18
+ return elems.map do |elem|
19
+ if elem.is_a?(Hash)
20
+ elem.values
21
+ else
22
+ elem
23
+ end
24
+ end.flatten
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ require "base64"
3
+
4
+ class Hash
5
+ def _base64encode(mutations)
6
+ self.fetch(:_base64encode, "").then do |value|
7
+ return Base64.encode64(value.mutate(mutations)).strip
8
+ end
9
+ end
10
+
11
+ def _base64decode(mutations)
12
+ self.fetch(:_base64decode, "").then do |value|
13
+ return Base64.decode64(value.mutate(mutations)).strip
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ include Funcml
5
+
6
+ def _first(mutations)
7
+ self.fetch(:_first).mutate(mutations).then do |elems|
8
+ return elems.first
9
+ end
10
+ end
11
+
12
+ def _last(mutations)
13
+ self.fetch(:_last).mutate(mutations).then do |elems|
14
+ if elems.is_a?(Hash)
15
+ return elems.values.last
16
+ else
17
+ return elems.last
18
+ end
19
+ end
20
+ end
21
+
22
+ def _tail(mutations)
23
+ self.fetch(:_tail).mutate(mutations).then do |elems|
24
+ return elems[0].last(elems[1])
25
+ end
26
+ end
27
+
28
+ def _head(mutations)
29
+ self.fetch(:_head).mutate(mutations).then do |elems|
30
+ return elems[0][0..(elems[1]-1)]
31
+ end
32
+ end
33
+
34
+ def _reverse(mutations)
35
+ self.fetch(:_reverse).mutate(mutations).then do |elems|
36
+ return elems.reverse
37
+ end
38
+ end
39
+
40
+ def _uniq(mutations)
41
+ self.fetch(:_uniq).mutate(mutations).then do |elems|
42
+ return elems.uniq
43
+ end
44
+ end
45
+
46
+ def _index(mutations)
47
+ self.fetch(:_index).mutate(mutations).then do |elems|
48
+ return elems[0].index(elems[1])
49
+ end
50
+ end
51
+
52
+ def _len(mutations)
53
+ self.fetch(:_len).then do |elems|
54
+ elems.mutate(mutations).length
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ def _add(mutations)
5
+ self.fetch(:_add, []).then do |numbers|
6
+ numbers.mutate(mutations).reduce(:+)
7
+ end
8
+ end
9
+
10
+ def _sub(mutations)
11
+ self.fetch(:_sub, []).then do |numbers|
12
+ numbers.mutate(mutations).reduce(:-)
13
+ end
14
+ end
15
+
16
+ def _div(mutations)
17
+ self.fetch(:_div, []).then do |numbers|
18
+ numbers.mutate(mutations).reduce(:/)
19
+ end
20
+ end
21
+
22
+ def _mod(mutations)
23
+ self.fetch(:_mod).then do |numbers|
24
+ first, second = numbers.mutate(mutations)
25
+ first % second
26
+ end
27
+ end
28
+
29
+ def _mul(mutations)
30
+ self.fetch(:_mul, []).then do |numbers|
31
+ numbers.mutate(mutations).reduce(:*)
32
+ end
33
+ end
34
+
35
+ def _min(mutations)
36
+ self.fetch(:_min, []).then do |numbers|
37
+ numbers.mutate(mutations).min
38
+ end
39
+ end
40
+
41
+ def _max(mutations)
42
+ self.fetch(:_max, []).then do |numbers|
43
+ numbers.mutate(mutations).max
44
+ end
45
+ end
46
+
47
+ def _floor(mutations)
48
+ self.fetch(:_floor).then do |number|
49
+ number.mutate(mutations).floor
50
+ end
51
+ end
52
+
53
+ def _ceil(mutations)
54
+ self.fetch(:_ceil).then do |number|
55
+ number.mutate(mutations).ceil
56
+ end
57
+ end
58
+
59
+ def _round(mutations)
60
+ self.fetch(:_round).then do |number|
61
+ number.mutate(mutations).round
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+
5
+ class Hash
6
+ include Funcml
7
+
8
+ def _time(mutations)
9
+ self.fetch(:_time).then do |blk|
10
+ _value = blk.fetch(:value)
11
+ _format = blk.fetch(:format, "%d/%m/%Y %H:%M:%S")
12
+
13
+ _value.mutate(mutations).then do |value|
14
+ return Time.parse(value).strftime(_format.mutate(mutations))
15
+ end
16
+ end
17
+ end
18
+
19
+ def _ago(mutations)
20
+ self.fetch(:_ago).then do |blk|
21
+ unless blk.is_a?(Integer)
22
+ raise IncorrectSecondsException, "_ago only supports seconds as value in #{self.to_s}"
23
+ end
24
+
25
+ (Time.now - blk).to_s
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ include Funcml
5
+
6
+ def mutate(mutations = {})
7
+ # dup is here to avoid iteration error on #delete/#merge
8
+ self.dup.each do |key, value|
9
+ case key
10
+ in /^_.*$/
11
+ # recursive mutation of result from pattern-matched _method
12
+ # once recursively mutated, we return the final object by guard
13
+ # clause instead of mutating the current object.
14
+ return self.send(key, mutations)
15
+ .mutate(mutations)
16
+ else
17
+ # no monkey-patch method found (_ prefix), we mutate anyway
18
+ # in case of variables or sub-functions.
19
+ self[key] = value.mutate(mutations)
20
+ end
21
+ end
22
+
23
+ self
24
+ end
25
+
26
+ def _if(mutations)
27
+ _runcond = Proc.new do |cond, mutations|
28
+ case cond
29
+ in {in: [needle, haystack]}
30
+ haystack.mutate(mutations).include?(needle.mutate(mutations))
31
+
32
+ in {null: vars}
33
+ vars.all? {|x| x.mutate(mutations).nil? }
34
+
35
+ in {present: vars}
36
+ vars.all? {|x| !x.mutate(mutations).nil? }
37
+
38
+ in {eq: [first, second]}
39
+ first.mutate(mutations).eql?(second.mutate(mutations))
40
+
41
+ in {ne: [first, second]}
42
+ !first.mutate(mutations).eql?(second.mutate(mutations))
43
+
44
+ in {gt: [first, second]}
45
+ first.mutate(mutations) > second.mutate(mutations)
46
+
47
+ in {lt: [first, second]}
48
+ first.mutate(mutations) < second.mutate(mutations)
49
+
50
+ in {ge: [first, second]}
51
+ first.mutate(mutations) >= second.mutate(mutations)
52
+
53
+ in {le: [first, second]}
54
+ first.mutate(mutations) <= second.mutate(mutations)
55
+
56
+ # or should evaluated by top-level if as true or false.
57
+ in {or: or_conds}
58
+ or_conds.any? do |cond|
59
+ _runcond.call(cond, mutations)
60
+ end
61
+
62
+ else
63
+ raise UnknownConditionException, "#{cond.to_s} is not a valid condition"
64
+ end
65
+ end
66
+
67
+ self.fetch(:_if).then do |conditions|
68
+ all_conditions_state = conditions.all? do |cond|
69
+ _runcond.call(cond, mutations)
70
+ end
71
+
72
+
73
+ if all_conditions_state
74
+ self.delete(:_if)
75
+ self.delete(:_else)
76
+ return self
77
+ else
78
+ return self[:_else] # returns nil if nothing has been set.
79
+ end
80
+
81
+ nil
82
+ end
83
+ end
84
+
85
+ def _loop(mutations)
86
+ self.fetch(:_loop).then do |_loop|
87
+ items = _loop.fetch(:items, []).mutate(mutations)
88
+ _results = []
89
+
90
+ # guard clause related to allowed types
91
+ unless items.is_a?(Array)
92
+ raise LoopTypeException, "_loop only supports Array as items"
93
+ end
94
+
95
+ # always mutate all items as they could be variable calling hashes.
96
+ # when caller is a string, will be callable as $item for String
97
+ # when caller is a Hash, will be callable as $item.path.to.value for String
98
+ items.each do |item|
99
+ _results << _loop[:block]
100
+ .dup # required to avoid duplicates in code
101
+ .mutate(mutations.merge(item: item))
102
+ end
103
+
104
+ return _results
105
+ end
106
+ end
107
+
108
+ def _until(mutations)
109
+ _results = []
110
+ amount = self.fetch(:_until)
111
+ amount.times do |i|
112
+ _results << self.dup.select{|k, v| k != :_until}
113
+ .mutate(mutations.merge(item: i))
114
+ end
115
+
116
+ return _results
117
+ end
118
+
119
+ # _sum takes and mutates all elements in array and
120
+ # sums them.
121
+ # eg: {_sum: [1, 2, 3]} = 6
122
+ def _sum(mutations)
123
+ self.fetch(:_sum).map do |item|
124
+ item.mutate(mutations)
125
+ end.sum
126
+ end
127
+
128
+ # _merge merges a hash found at mutation path with caller hash
129
+ # and removes the _merge reference.
130
+ # eg: {key: value, _merge: path.to_mutation } = {key: value, imported_key: value}
131
+ def _merge(mutations)
132
+ self.fetch(:_merge).mutate(mutations).then do |result|
133
+ self.merge!(result).then do
134
+ self.delete(:_merge)
135
+ end
136
+ end
137
+
138
+ self
139
+ end
140
+
141
+ # _concat concatenates items elements as a string with sep as separator.
142
+ # eg: {_concat: {items: ["a", "b", "c"], sep: " "}} = "a b c"
143
+ def _concat(mutations)
144
+ self.fetch(:_concat).then do |concat|
145
+ return concat.fetch(:items, [])
146
+ .mutate(mutations)
147
+ .join(concat.fetch(:sep, "").mutate(mutations))
148
+ end
149
+ end
150
+
151
+ def _readfile(mutations)
152
+ self.fetch(:_readfile).then do |path|
153
+ File.read(path)
154
+ end
155
+ end
156
+
157
+ def dig_from_str(path, mutations)
158
+ path_array_sym = path.split('.').map do |sub|
159
+ sub.to_sym
160
+ end
161
+
162
+ self.dig(*path_array_sym).mutate(mutations)
163
+ end
164
+
165
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Integer
4
+ def mutate(_)
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NilClass
4
+ def mutate(_)
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ require "securerandom"
3
+
4
+ class String
5
+ include Funcml
6
+
7
+ def mutate(mutations)
8
+ if self.start_with?('$')
9
+
10
+ return Time.now.to_s if self.eql?('$now')
11
+ return SecureRandom.uuid if self.eql?('$uuidv4')
12
+
13
+ mutations.dig_from_str(self.gsub('$', ''), mutations).then do |value|
14
+ raise MutationException, "`#{self}` not found in mutations, available mutations: #{mutations.to_s}" if value.nil?
15
+ return value.mutate(mutations)
16
+ end
17
+ end
18
+
19
+ self
20
+ end
21
+
22
+ def dig(_)
23
+ self
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Symbol
4
+ def mutate(_)
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TrueClass
4
+ def mutate(_)
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Funcml
4
+ VERSION = "0.9.0"
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "funcml-core/version"
4
+ require_relative "funcml-core/patch/hash"
5
+ require_relative "funcml-core/patch/string"
6
+ require_relative "funcml-core/patch/nil"
7
+ require_relative "funcml-core/patch/false"
8
+ require_relative "funcml-core/patch/true"
9
+ require_relative "funcml-core/patch/array"
10
+ require_relative "funcml-core/patch/integer"
11
+ require_relative "funcml-core/patch/symbol"
12
+ require_relative "funcml-core/patch/float"
13
+
14
+ require_relative "funcml-core/patch/funcs/encoding"
15
+ require_relative "funcml-core/patch/funcs/cryptography"
16
+ require_relative "funcml-core/patch/funcs/time"
17
+ require_relative "funcml-core/patch/funcs/dictionary"
18
+ require_relative "funcml-core/patch/funcs/list"
19
+ require_relative "funcml-core/patch/funcs/math"
20
+ require_relative "funcml-core/patch/funcs/cast"
21
+
22
+ module Funcml
23
+ class Error < StandardError; end
24
+ class MutationException < Error; end
25
+ class LoopTypeException < Error; end
26
+ class UnknownConditionException < Error; end
27
+ class MissingEncryptionKeyException < Error; end
28
+ class IncorrectSecondsException < Error; end
29
+ # Your code goes here...
30
+ end
data/sig/funcml.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Funcml
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: funcml-core
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Mimopotato
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-07-14 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A library that implements mutations on data-structures
14
+ email:
15
+ - 173955441+mimopotato@users.noreply.github.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE.txt
21
+ - README.md
22
+ - Rakefile
23
+ - lib/funcml-core.rb
24
+ - lib/funcml-core/patch/array.rb
25
+ - lib/funcml-core/patch/false.rb
26
+ - lib/funcml-core/patch/float.rb
27
+ - lib/funcml-core/patch/funcs/cast.rb
28
+ - lib/funcml-core/patch/funcs/cryptography.rb
29
+ - lib/funcml-core/patch/funcs/dictionary.rb
30
+ - lib/funcml-core/patch/funcs/encoding.rb
31
+ - lib/funcml-core/patch/funcs/list.rb
32
+ - lib/funcml-core/patch/funcs/math.rb
33
+ - lib/funcml-core/patch/funcs/time.rb
34
+ - lib/funcml-core/patch/hash.rb
35
+ - lib/funcml-core/patch/integer.rb
36
+ - lib/funcml-core/patch/nil.rb
37
+ - lib/funcml-core/patch/string.rb
38
+ - lib/funcml-core/patch/symbol.rb
39
+ - lib/funcml-core/patch/true.rb
40
+ - lib/funcml-core/version.rb
41
+ - sig/funcml.rbs
42
+ homepage: https://github.com/mimopotato/funcml-lang
43
+ licenses:
44
+ - MIT
45
+ metadata:
46
+ allowed_push_host: https://rubygems.org
47
+ homepage_uri: https://github.com/mimopotato/funcml-lang
48
+ source_code_uri: https://github.com/mimopotato/funcml-core
49
+ changelog_uri: https://github.com/mimopotato/funcml-core
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 2.7.0
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.3.3
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: funcml-core
69
+ test_files: []