persistent-dmnd 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 +7 -0
- data/.gitignore +28 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +23 -0
- data/CODE_OF_CONDUCT.adoc +72 -0
- data/Gemfile +1 -0
- data/LICENSE +21 -0
- data/README.adoc +499 -0
- data/Rakefile +6 -0
- data/UPSTREAM_TODO.adoc +132 -0
- data/bin/pry +21 -0
- data/bin/rspec +21 -0
- data/gems.rb +8 -0
- data/lib/persistent-dmnd.rb +32 -0
- data/lib/persistent-/360/237/222/216.rb +110 -0
- data/lib/persistent_dmnd/array.rb +100 -0
- data/lib/persistent_dmnd/concurrent_ruby_support.rb +88 -0
- data/lib/persistent_dmnd/dmndifier.rb +74 -0
- data/lib/persistent_dmnd/everywhere.rb +35 -0
- data/lib/persistent_dmnd/hash.rb +125 -0
- data/lib/persistent_dmnd/is_persistent.rb +39 -0
- data/lib/persistent_dmnd/jruby_workaround.rb +107 -0
- data/lib/persistent_dmnd/ruby_1_9_and_2_0_support.rb +47 -0
- data/lib/persistent_dmnd/self_conversion.rb +44 -0
- data/lib/persistent_dmnd/set.rb +92 -0
- data/lib/persistent_dmnd/version.rb +34 -0
- data/persistent-dmnd.gemspec +63 -0
- metadata +169 -0
data/Rakefile
ADDED
data/UPSTREAM_TODO.adoc
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
= Upstream ToDo
|
2
|
+
|
3
|
+
Notes for pushing things upstream.
|
4
|
+
|
5
|
+
== Hamster
|
6
|
+
|
7
|
+
=== Wishlist
|
8
|
+
|
9
|
+
* Insertion order for Hamster::Hash similarly to Ruby hashes
|
10
|
+
* Insertion order for Hamster::Set? Or alternatively if Hash supports
|
11
|
+
it, we can trivially implement a Set using a Hash, if it provides that option.
|
12
|
+
|
13
|
+
=== Push Set </+++<=+++/>=/> upstream, and drop +++<=>+++ from Set
|
14
|
+
|
15
|
+
This makes Sets behave like regular Ruby Sets.
|
16
|
+
|
17
|
+
=== Fix warnings
|
18
|
+
|
19
|
+
Several warnings when executing specs:
|
20
|
+
|
21
|
+
----
|
22
|
+
/home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/hash.rb:470: warning: shadowing outer local variable - trie
|
23
|
+
/home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/trie.rb:220: warning: shadowing outer local variable - entry
|
24
|
+
/home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/set.rb:4: warning: loading in progress, circular require considered harmful - /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/hash.rb
|
25
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/bin/ruby_executable_hooks:15:in `<main>'
|
26
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/bin/ruby_executable_hooks:15:in `eval'
|
27
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/bin/rspec:23:in `<main>'
|
28
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/bin/rspec:23:in `load'
|
29
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/exe/rspec:4:in `<top (required)>'
|
30
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:45:in `invoke'
|
31
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:71:in `run'
|
32
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:86:in `run'
|
33
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:100:in `setup'
|
34
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1494:in `load_spec_files'
|
35
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1494:in `each'
|
36
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1496:in `block in load_spec_files'
|
37
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1924:in `load_spec_file_handling_errors'
|
38
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1924:in `load'
|
39
|
+
from /home/knuckles/ruby/persistent-dmnd/spec/unit/array_spec.rb:1:in `<top (required)>'
|
40
|
+
from /home/knuckles/ruby/persistent-dmnd/spec/unit/array_spec.rb:1:in `require'
|
41
|
+
from /home/knuckles/ruby/persistent-dmnd/lib/persistent-💎.rb:3:in `<top (required)>'
|
42
|
+
from /home/knuckles/ruby/persistent-dmnd/lib/persistent-💎.rb:3:in `require'
|
43
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster.rb:1:in `<top (required)>'
|
44
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster.rb:1:in `require'
|
45
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/core_ext.rb:1:in `<top (required)>'
|
46
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/core_ext.rb:1:in `require'
|
47
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/core_ext/enumerable.rb:1:in `<top (required)>'
|
48
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/core_ext/enumerable.rb:1:in `require'
|
49
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/list.rb:7:in `<top (required)>'
|
50
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/list.rb:7:in `require'
|
51
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/hash.rb:5:in `<top (required)>'
|
52
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/hash.rb:5:in `require'
|
53
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/set.rb:4:in `<top (required)>'
|
54
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/set.rb:4:in `require'
|
55
|
+
/home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/vector.rb:3: warning: loading in progress, circular require considered harmful - /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/hash.rb
|
56
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/bin/ruby_executable_hooks:15:in `<main>'
|
57
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/bin/ruby_executable_hooks:15:in `eval'
|
58
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/bin/rspec:23:in `<main>'
|
59
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/bin/rspec:23:in `load'
|
60
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/exe/rspec:4:in `<top (required)>'
|
61
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:45:in `invoke'
|
62
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:71:in `run'
|
63
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:86:in `run'
|
64
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:100:in `setup'
|
65
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1494:in `load_spec_files'
|
66
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1494:in `each'
|
67
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1496:in `block in load_spec_files'
|
68
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1924:in `load_spec_file_handling_errors'
|
69
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1924:in `load'
|
70
|
+
from /home/knuckles/ruby/persistent-dmnd/spec/unit/array_spec.rb:1:in `<top (required)>'
|
71
|
+
from /home/knuckles/ruby/persistent-dmnd/spec/unit/array_spec.rb:1:in `require'
|
72
|
+
from /home/knuckles/ruby/persistent-dmnd/lib/persistent-💎.rb:3:in `<top (required)>'
|
73
|
+
from /home/knuckles/ruby/persistent-dmnd/lib/persistent-💎.rb:3:in `require'
|
74
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster.rb:1:in `<top (required)>'
|
75
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster.rb:1:in `require'
|
76
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/core_ext.rb:1:in `<top (required)>'
|
77
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/core_ext.rb:1:in `require'
|
78
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/core_ext/enumerable.rb:1:in `<top (required)>'
|
79
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/core_ext/enumerable.rb:1:in `require'
|
80
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/list.rb:7:in `<top (required)>'
|
81
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/list.rb:7:in `require'
|
82
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/hash.rb:6:in `<top (required)>'
|
83
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/hash.rb:6:in `require'
|
84
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/vector.rb:3:in `<top (required)>'
|
85
|
+
from /home/knuckles/.rvm/gems/ruby-2.4.2/gems/hamster-3.0.0/lib/hamster/vector.rb:3:in `require'
|
86
|
+
|
87
|
+
----
|
88
|
+
|
89
|
+
=== Maybe make `Vector` and `SortedSet` reuse empty instances?
|
90
|
+
|
91
|
+
See commit 4fe1035ff9771a1bc7394ea7aa7bb3fb443794b0 for details.
|
92
|
+
|
93
|
+
=== Maybe make `SortedSet#to_set` return a regular Ruby set?
|
94
|
+
|
95
|
+
This matches with the `#to_ary` and `#to_hash` behavior on `Vector`/`Hash`.
|
96
|
+
|
97
|
+
See commit 6152f5389f61ab9d029b8dfd45d319044ab26062 for details.
|
98
|
+
|
99
|
+
=== Make `Vector` and `Hash` `#to_set` return a regular Ruby set
|
100
|
+
|
101
|
+
As with the above case, this matches with the `#to_a`/`#to_ary`/`#to_h`/
|
102
|
+
`to_hash` behavior that returns regular ruby data structures.
|
103
|
+
|
104
|
+
=== Allow `Set` to be compared with custom types
|
105
|
+
|
106
|
+
It does not make a lot of sense for Hamster to enforce that a `Set` can only
|
107
|
+
be `==` to other `Set` instances.
|
108
|
+
|
109
|
+
=== `Hash` should not implement `#to_ary`
|
110
|
+
|
111
|
+
`#to_ary` should only be implemented by objects which really can be seen as
|
112
|
+
arrays, not for those which can be converted into arrays, so this is a big and
|
113
|
+
clear mistake.
|
114
|
+
|
115
|
+
=== `Set` should use the `Kernel.+++<=>+++` behavior, not just undef it
|
116
|
+
|
117
|
+
[source,ruby]
|
118
|
+
----
|
119
|
+
def <=>(other)
|
120
|
+
self == other ? 0 : nil
|
121
|
+
end
|
122
|
+
----
|
123
|
+
|
124
|
+
=== Fix `Hash` comparison with Ruby hashes using `<`/`+++<=+++` breaks on Ruby 2.2 or older
|
125
|
+
|
126
|
+
Because the default implementation of this methods is `other > self` or `other >= self`, this breaks on older rubies as Hash does not implement these methods.
|
127
|
+
|
128
|
+
By relying supplying our own comparison code (similar to `>`/`>=`) we can workaround this.
|
129
|
+
|
130
|
+
=== Fix unneeded complex comparison in `Hash#>`
|
131
|
+
|
132
|
+
Instead of implementing it as `self != other && self >= other` and thus requiring twice the iterations/comparisons, this can just be `self.size > other.size`.
|
data/bin/pry
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'pry' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
12
|
+
load(bundle_binstub) if File.file?(bundle_binstub)
|
13
|
+
|
14
|
+
require "pathname"
|
15
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
16
|
+
Pathname.new(__FILE__).realpath)
|
17
|
+
|
18
|
+
require "rubygems"
|
19
|
+
require "bundler/setup"
|
20
|
+
|
21
|
+
load Gem.bin_path("pry", "pry")
|
data/bin/rspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
12
|
+
load(bundle_binstub) if File.file?(bundle_binstub)
|
13
|
+
|
14
|
+
require "pathname"
|
15
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
16
|
+
Pathname.new(__FILE__).realpath)
|
17
|
+
|
18
|
+
require "rubygems"
|
19
|
+
require "bundler/setup"
|
20
|
+
|
21
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/gems.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Persistent-💎: Ruby gem for easily creating immutable data structures
|
4
|
+
# Copyright (c) 2017 Ivo Anjo <ivo.anjo@ist.utl.pt>
|
5
|
+
#
|
6
|
+
# This file is part of Persistent-💎.
|
7
|
+
#
|
8
|
+
# MIT License
|
9
|
+
#
|
10
|
+
# Copyright (c) 2017 Ivo Anjo
|
11
|
+
#
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
13
|
+
# of this software and associated documentation files (the "Software"), to deal
|
14
|
+
# in the Software without restriction, including without limitation the rights
|
15
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
16
|
+
# copies of the Software, and to permit persons to whom the Software is
|
17
|
+
# furnished to do so, subject to the following conditions:
|
18
|
+
#
|
19
|
+
# The above copyright notice and this permission notice shall be included in all
|
20
|
+
# copies or substantial portions of the Software.
|
21
|
+
#
|
22
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
23
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
24
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
25
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
26
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
27
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
28
|
+
# SOFTWARE.
|
29
|
+
|
30
|
+
# frozen_string_literal: true
|
31
|
+
|
32
|
+
require 'persistent-💎'
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Persistent-💎: Ruby gem for easily creating immutable data structures
|
4
|
+
# Copyright (c) 2017 Ivo Anjo <ivo.anjo@ist.utl.pt>
|
5
|
+
#
|
6
|
+
# This file is part of Persistent-💎.
|
7
|
+
#
|
8
|
+
# MIT License
|
9
|
+
#
|
10
|
+
# Copyright (c) 2017 Ivo Anjo
|
11
|
+
#
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
13
|
+
# of this software and associated documentation files (the "Software"), to deal
|
14
|
+
# in the Software without restriction, including without limitation the rights
|
15
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
16
|
+
# copies of the Software, and to permit persons to whom the Software is
|
17
|
+
# furnished to do so, subject to the following conditions:
|
18
|
+
#
|
19
|
+
# The above copyright notice and this permission notice shall be included in all
|
20
|
+
# copies or substantial portions of the Software.
|
21
|
+
#
|
22
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
23
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
24
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
25
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
26
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
27
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
28
|
+
# SOFTWARE.
|
29
|
+
|
30
|
+
# frozen_string_literal: true
|
31
|
+
|
32
|
+
require 'persistent_dmnd/version'
|
33
|
+
require 'persistent_dmnd/array'
|
34
|
+
require 'persistent_dmnd/hash'
|
35
|
+
require 'persistent_dmnd/set'
|
36
|
+
require 'persistent_dmnd/dmndifier'
|
37
|
+
require 'persistent_dmnd/jruby_workaround'
|
38
|
+
|
39
|
+
module Persistent💎
|
40
|
+
include JRubyWorkaround
|
41
|
+
|
42
|
+
def self.included(klass)
|
43
|
+
# Make methods on this module also available inside classes (e.g. not just in instances)
|
44
|
+
klass.extend(self)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Not very useful, but more of a "why not?" thing
|
48
|
+
def self.prepended(klass)
|
49
|
+
included(klass)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Pretty syntax for creating the persistent structures
|
53
|
+
|
54
|
+
# Create a new persistent array
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# my_array = a💎[1, 2, 3]
|
58
|
+
# my_array = a💎.new([1, 2, 3])
|
59
|
+
# # => Persistent💎::Array[1, 2, 3]
|
60
|
+
#
|
61
|
+
def a💎
|
62
|
+
Persistent💎::Array
|
63
|
+
end
|
64
|
+
alias_method :aDmnd, :a💎
|
65
|
+
|
66
|
+
# Create a new persistent hash
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# my_hash = h💎[hello: 'world']
|
70
|
+
# my_hash = h💎.new(hello: 'world')
|
71
|
+
# # => Persistent💎::Hash[:hello => "world"]
|
72
|
+
#
|
73
|
+
def h💎
|
74
|
+
Persistent💎::Hash
|
75
|
+
end
|
76
|
+
alias_method :hDmnd, :h💎
|
77
|
+
|
78
|
+
# Create a new persistent set
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# my_set = s💎[:hello, :world]
|
82
|
+
# my_set = s💎.new([:hello, :world])
|
83
|
+
# # => Persistent💎::Set[:hello, :world]
|
84
|
+
#
|
85
|
+
def s💎
|
86
|
+
Persistent💎::Set
|
87
|
+
end
|
88
|
+
alias_method :sDmnd, :s💎
|
89
|
+
|
90
|
+
# Pretty syntax to making something persistent
|
91
|
+
|
92
|
+
# Make argument persistent, if possible
|
93
|
+
#
|
94
|
+
# * Already-persistent arguments are left the same
|
95
|
+
# * Calls #to_💎 or #to_dmnd for objects that already know how to convert themselves into persistent structures
|
96
|
+
# * Converts objects that answer to #to_ary into persistent arrays
|
97
|
+
# * Converts objects that answer to #to_hash into persistent hashes
|
98
|
+
# * Converts objects that answer to #each_pair into persistent hashes
|
99
|
+
# * Converts strings into immutable Strings (without modifying the original String)
|
100
|
+
# * Converts objects that answer to #to_str into frozen Strings
|
101
|
+
# * Converts sets (e.g. something that #is_a?(::Set) or answers to #to_set) into persistent sets
|
102
|
+
# * Converts Hamster and Concurrent (from concurrent-ruby) data structures to their persistent counterparts
|
103
|
+
#
|
104
|
+
def 💎ify
|
105
|
+
Persistent💎::Dmndifier
|
106
|
+
end
|
107
|
+
alias_method :dmndify, :💎ify
|
108
|
+
end
|
109
|
+
|
110
|
+
PersistentDmnd = Persistent💎
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Persistent-💎: Ruby gem for easily creating immutable data structures
|
4
|
+
# Copyright (c) 2017 Ivo Anjo <ivo.anjo@ist.utl.pt>
|
5
|
+
#
|
6
|
+
# This file is part of Persistent-💎.
|
7
|
+
#
|
8
|
+
# MIT License
|
9
|
+
#
|
10
|
+
# Copyright (c) 2017 Ivo Anjo
|
11
|
+
#
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
13
|
+
# of this software and associated documentation files (the "Software"), to deal
|
14
|
+
# in the Software without restriction, including without limitation the rights
|
15
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
16
|
+
# copies of the Software, and to permit persons to whom the Software is
|
17
|
+
# furnished to do so, subject to the following conditions:
|
18
|
+
#
|
19
|
+
# The above copyright notice and this permission notice shall be included in all
|
20
|
+
# copies or substantial portions of the Software.
|
21
|
+
#
|
22
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
23
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
24
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
25
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
26
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
27
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
28
|
+
# SOFTWARE.
|
29
|
+
|
30
|
+
# frozen_string_literal: true
|
31
|
+
|
32
|
+
require 'persistent_dmnd/self_conversion'
|
33
|
+
require 'persistent_dmnd/is_persistent'
|
34
|
+
require 'persistent_dmnd/concurrent_ruby_support'
|
35
|
+
require 'persistent_dmnd/jruby_workaround'
|
36
|
+
|
37
|
+
require 'hamster'
|
38
|
+
require 'set'
|
39
|
+
|
40
|
+
module Persistent💎
|
41
|
+
class Array < Hamster::Vector
|
42
|
+
include SelfConversion
|
43
|
+
include IsPersistent
|
44
|
+
include JRubyWorkaround
|
45
|
+
include Persistent💎
|
46
|
+
|
47
|
+
def self.[](*items)
|
48
|
+
if items.empty?
|
49
|
+
empty
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return Concurrent::Array with contents of Persistent💎::Array
|
56
|
+
#
|
57
|
+
# @example
|
58
|
+
# my_array = a💎[:hello, :world]
|
59
|
+
# my_concurrent_array = my_array.to_concurrent_array
|
60
|
+
#
|
61
|
+
def to_concurrent_array
|
62
|
+
ConcurrentRubySupport::ensure_concurrent_ruby_loaded
|
63
|
+
Concurrent::Array.new(self)
|
64
|
+
end
|
65
|
+
alias :to_concurrent :to_concurrent_array
|
66
|
+
|
67
|
+
# Return Concurrent::Tuple with contents of Persistent💎::Array
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# my_array = a💎[:hello, :world]
|
71
|
+
# my_concurrent_tuple = my_array.to_concurrent_tuple
|
72
|
+
# # => #<Concurrent::Tuple @size=2, @tuple=[<#Concurrent::AtomicReference value:hello>, <#Concurrent::AtomicReference value:world>]>
|
73
|
+
#
|
74
|
+
def to_concurrent_tuple
|
75
|
+
ConcurrentRubySupport::ensure_concurrent_ruby_loaded
|
76
|
+
each.with_index.each_with_object(Concurrent::Tuple.new(size)) do |(item, index), result|
|
77
|
+
result.set(index, item)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_set
|
82
|
+
::Set.new(self)
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_a💎
|
86
|
+
self
|
87
|
+
end
|
88
|
+
alias_method :to_aDmnd, :to_a💎
|
89
|
+
|
90
|
+
def to_h💎
|
91
|
+
h💎[self]
|
92
|
+
end
|
93
|
+
alias_method :to_hDmnd, :to_h💎
|
94
|
+
|
95
|
+
def to_s💎
|
96
|
+
s💎[*self]
|
97
|
+
end
|
98
|
+
alias_method :to_sDmnd, :to_s💎
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Persistent-💎: Ruby gem for easily creating immutable data structures
|
4
|
+
# Copyright (c) 2017 Ivo Anjo <ivo.anjo@ist.utl.pt>
|
5
|
+
#
|
6
|
+
# This file is part of Persistent-💎.
|
7
|
+
#
|
8
|
+
# MIT License
|
9
|
+
#
|
10
|
+
# Copyright (c) 2017 Ivo Anjo
|
11
|
+
#
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
13
|
+
# of this software and associated documentation files (the "Software"), to deal
|
14
|
+
# in the Software without restriction, including without limitation the rights
|
15
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
16
|
+
# copies of the Software, and to permit persons to whom the Software is
|
17
|
+
# furnished to do so, subject to the following conditions:
|
18
|
+
#
|
19
|
+
# The above copyright notice and this permission notice shall be included in all
|
20
|
+
# copies or substantial portions of the Software.
|
21
|
+
#
|
22
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
23
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
24
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
25
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
26
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
27
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
28
|
+
# SOFTWARE.
|
29
|
+
|
30
|
+
# frozen_string_literal: true
|
31
|
+
|
32
|
+
require 'thread'
|
33
|
+
|
34
|
+
module Persistent💎
|
35
|
+
# Simple module that attempts to load concurrent-ruby, and then stores the result for quick lookup
|
36
|
+
# This way we take care of loading concurrent-ruby ONLY when the library client asks us to, thus not bloating
|
37
|
+
# applications that don't need concurrent-ruby loaded but still having a great user experience
|
38
|
+
module ConcurrentRubySupport
|
39
|
+
REQUIRE_MUTEX = Mutex.new
|
40
|
+
private_constant :REQUIRE_MUTEX
|
41
|
+
|
42
|
+
class << self
|
43
|
+
def ensure_concurrent_ruby_loaded
|
44
|
+
loaded = @concurrent_loaded
|
45
|
+
|
46
|
+
if loaded == :success
|
47
|
+
return true
|
48
|
+
elsif loaded == :failure
|
49
|
+
raise_no_concurrent_ruby
|
50
|
+
end
|
51
|
+
|
52
|
+
begin
|
53
|
+
REQUIRE_MUTEX.synchronize do # Avoid require races
|
54
|
+
require 'concurrent'
|
55
|
+
end
|
56
|
+
mark_as_success
|
57
|
+
true
|
58
|
+
rescue LoadError
|
59
|
+
mark_as_failure
|
60
|
+
raise_no_concurrent_ruby
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def raise_no_concurrent_ruby
|
67
|
+
raise(NotImplementedError,
|
68
|
+
'concurrent-ruby gem is not available, please install it in order to use #to_concurrent and #to_concurrent_* methods')
|
69
|
+
end
|
70
|
+
|
71
|
+
# The following methods are only for internal and test usage. Please do not use them :)
|
72
|
+
|
73
|
+
def mark_as_success
|
74
|
+
@concurrent_loaded = :success
|
75
|
+
end
|
76
|
+
|
77
|
+
def mark_as_failure
|
78
|
+
@concurrent_loaded = :failure
|
79
|
+
end
|
80
|
+
|
81
|
+
def reset_state
|
82
|
+
@concurrent_loaded = nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
reset_state
|
87
|
+
end
|
88
|
+
end
|