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.
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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")
@@ -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,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ # Specify ffi version to avoid dependency issues when switching between MRI
6
+ # and JRuby with the same gems.lock
7
+ # Only used in development
8
+ gem 'ffi', '~> 1.9.18'
@@ -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