funcml-core 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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: []