persistent-dmnd 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 54b67123bdfe4c297e51b64be972627bbe928facb6b511ffb6f4d6c503190d35
4
+ data.tar.gz: 9ae346225bfe53de7a2954d0024a90c553757737dd197d1a4fa98bd144611fff
5
+ SHA512:
6
+ metadata.gz: 4cfee400e6a85861aa5048b19b56bde067c1644a761750546cbf469ef7098ecef8511e407405ae7008712258ebbb8852ad34ae70f26c8a78bfbe17663f4133f0
7
+ data.tar.gz: 4f5ab905f9ec7e810f463187d76f24d08b0000129c17b90746f5a5f0e68405deaf4275b8c5eb2a7d6badafd64e34debb6b95a8e5972eba04f2e683fd2b0375e8
@@ -0,0 +1,28 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Documentation cache and generated files:
17
+ /.yardoc/
18
+ /_yardoc/
19
+ /doc/
20
+ /rdoc/
21
+
22
+ ## Environment normalization:
23
+ /.bundle/
24
+ /vendor/bundle
25
+ /lib/bundler/man/
26
+
27
+ gems.locked
28
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
@@ -0,0 +1 @@
1
+ ruby-2.5.0
@@ -0,0 +1,23 @@
1
+ language: ruby
2
+ sudo: false
3
+
4
+ rvm:
5
+ - jruby-9.1.15.0
6
+ - 2.5
7
+ - 2.4
8
+ - jruby-1.7.9
9
+ - 1.9.3
10
+ - 2.3
11
+ - 2.2
12
+ - 2.1
13
+ - 2.0.0
14
+ - jruby-9.0.0.0
15
+ - jruby-1.7.27
16
+ - ruby-head
17
+ - jruby-head
18
+
19
+ matrix:
20
+ allow_failures:
21
+ - rvm: ruby-head
22
+ - rvm: jruby-head
23
+ - rvm: 2.5
@@ -0,0 +1,72 @@
1
+ = Contributor Covenant Code of Conduct
2
+
3
+ == Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ == Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ == Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ == Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ == Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at ivo.anjo@ist.utl.pt. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ == Attribution
69
+
70
+ This Code of Conduct is adapted from the
71
+ http://contributor-covenant.org[Contributor Covenant], version 1.4, available at
72
+ http://contributor-covenant.org/version/1/4/.
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ ./gems.rb
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Ivo Anjo
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,499 @@
1
+ = Persistent-💎: Because Immutable Data Is Forever
2
+ :toc:
3
+ :toc-placement: macro
4
+ :toclevels: 4
5
+ :toc-title:
6
+
7
+ image:https://travis-ci.org/ivoanjo/persistent-dmnd.svg?branch=master["Build Status", link="https://travis-ci.org/ivoanjo/persistent-dmnd"] image:https://gemnasium.com/badges/github.com/ivoanjo/persistent-dmnd.svg["Dependency Status", link="https://gemnasium.com/github.com/ivoanjo/persistent-dmnd"]
8
+
9
+ Are you tired of calling `.freeze` on your data structures (or your colleagues forgetting to do so)? +
10
+ Do you wish Ruby had a literal for creating immutable arrays?
11
+
12
+ Then persistent-💎 aka _persistent diamond_ is for you!
13
+
14
+ Persistent-💎 gives you a very tidy way of creating *immutable*...
15
+
16
+ * *Arrays*:
17
+ +
18
+ [source,ruby]
19
+ ----
20
+ my_array = a💎[1, 2, 3]
21
+ ----
22
+
23
+ * *Hashes*:
24
+ +
25
+ [source,ruby]
26
+ ----
27
+ my_hash = h💎[key1: 'foo', key2: 'bar']
28
+ ----
29
+
30
+ * *Sets*:
31
+ +
32
+ [source,ruby]
33
+ ----
34
+ my_set = s💎[:sephiroth, :kills, :aeris]
35
+ ----
36
+
37
+ ...and it behaves as you expect it to:
38
+
39
+ * You can compare immutable data structures with regular Ruby instances
40
+ +
41
+ [source,ruby]
42
+ ----
43
+ a💎[1, 2] == [1, 2] && h💎[key1: 'foo'] == {key1: 'foo'} && s💎[:hello] == Set.new([:hello])
44
+ # => true
45
+ ----
46
+
47
+ * You can compare immutable hashes with `<`/`+++<=+++`/`>=`/`>` and with regular Ruby hashes:
48
+ +
49
+ [source,ruby]
50
+ ----
51
+ h💎[a: 1] < h💎[a: 1, b: 2] && {a: 1, b: 2} < h💎[a: 1, b: 2, c: 3]
52
+ # => true
53
+ ----
54
+
55
+ * You can compare immutable sets with `<`/`+++<=+++`/`>=`/`>` and with regular Ruby sets:
56
+ +
57
+ [source,ruby]
58
+ ----
59
+ s💎[1] < s💎[1, 2] && Set.new([1, 2]) < s💎[1, 2, 3]
60
+ # => true
61
+ ----
62
+
63
+ * You can splat (`*`) immutable arrays:
64
+ +
65
+ [source,ruby]
66
+ ----
67
+ def sum(a, b, c)
68
+ a + b + c
69
+ end
70
+
71
+ sum(*a💎[1, 2, 39])
72
+ # => 42
73
+
74
+ sum(1, *a💎[2, 39])
75
+ # => 42
76
+ ----
77
+
78
+ * You can double-splat (`**`) immmutable hashes:
79
+ +
80
+ [source,ruby]
81
+ ----
82
+ def hello(name:, age:)
83
+ "Hello there #{name}, you are #{age} years old!"
84
+ end
85
+
86
+ hello(h💎[name: 'User', age: '50'])
87
+ # => "Hello there User, you are 50 years old!"
88
+
89
+ hello(name: 'Another User', **h💎[age: '50'])
90
+ # => "Hello there Another User, you are 50 years old!"
91
+ ----
92
+
93
+ Beyond being immutable, these data structures are thread-safe, and can be efficiently copied: when you "update" them, a new copy gets created that shares most of its structure with the original. Thus, creating new instances from existing structures is both memory-efficient and quite fast!
94
+
95
+ It also (_optionally!_) interoperates with the https://github.com/ruby-concurrency/concurrent-ruby[concurrent-ruby gem], for when you need that extra Oomph (or just thread-safe mutability). See <<concurrent-ruby-interoperability,below>> for more details.
96
+
97
+ Underneath the covers, persistent-💎 mostly builds atop the awesome https://github.com/hamstergem/hamster[hamster gem].
98
+ Big thanks to its equally-awesome authors!
99
+
100
+ Persistent-💎 is fully supported and tested on Ruby versions 1.9.3 to 2.5, and JRuby 1.7 to to 9.1. If we don't support your Ruby, it's probably a Python binary. Keep calm and 💎 away!
101
+
102
+ [discrete]
103
+ == Contents
104
+
105
+ toc::[]
106
+
107
+ == Installation
108
+
109
+ Add this line to your application's `gems.rb` or `Gemfile`:
110
+
111
+ [source,ruby]
112
+ ----
113
+ gem 'persistent-dmnd'
114
+ ----
115
+
116
+ And then execute:
117
+
118
+ [source,bash]
119
+ ----
120
+ $ bundle install
121
+ ----
122
+
123
+ Or install it yourself as:
124
+
125
+ [source,bash]
126
+ ----
127
+ $ gem install persistent-dmnd
128
+ ----
129
+
130
+ This gem is versioned according to http://semver.org/spec/v2.0.0.html[Semantic Versioning].
131
+
132
+ == Usage
133
+
134
+ To use persistent-💎, first load it:
135
+
136
+ [source,ruby]
137
+ ----
138
+ require 'persistent-💎'
139
+ # note: you can also use require 'persistent-dmnd'
140
+ ----
141
+
142
+ Persistent-💎 can be added as a module to individual classes (or even to other modules!):
143
+
144
+ [source,ruby]
145
+ ----
146
+ class FooController
147
+ include Persistent💎
148
+ # note: you can also use include PersistentDmnd
149
+
150
+ ARGUMENTS = a💎[:name, :address, :likes_icecream] # Usable inside this class...
151
+
152
+ def stuff
153
+ a💎[:stuff, :more_stuff] # ...and its methods
154
+ end
155
+ end
156
+ ----
157
+
158
+ Or you can add it to your whole application by just doing
159
+
160
+ [source,ruby]
161
+ ----
162
+ require 'persistent_dmnd/everywhere'
163
+
164
+ a💎[:freeeeeeedooooom] # usable everyhere in your application
165
+ ----
166
+
167
+ As you may have noticed, everywhere there is an `💎`, you can replace it with `dmnd`, e.g. `PersistentDmnd` instead of `Persistent💎` for the gem module and for `aDmnd[]` instead of `a💎[]` to create an array.
168
+
169
+ === Creating new persistent structures
170
+
171
+ ==== Array
172
+
173
+ Use `a💎[]` (or `aDmnd[]`) to create a new array:
174
+
175
+ [source,ruby]
176
+ ----
177
+ empty_array = a💎[]
178
+ # => Persistent💎::Array[]
179
+
180
+ my_array = a💎[:hello, :world]
181
+ # => Persistent💎::Array[:hello, :world]
182
+ ----
183
+
184
+ ==== Hash
185
+
186
+ Use `h💎[]` (or `hDmnd[]`) to create a new hash:
187
+
188
+ [source,ruby]
189
+ ----
190
+ empty_hash = h💎[]
191
+ # => Persistent💎::Hash[]
192
+
193
+ my_hash = h💎['hello' => 'world']
194
+ # => Persistent💎::Hash["hello" => "world"]
195
+ ----
196
+
197
+ ==== Set
198
+
199
+ Use `s💎[]` (or `sDmnd[]`) to create a new set:
200
+
201
+ [source,ruby]
202
+ ----
203
+ empty_set = s💎[]
204
+ # => Persistent💎::Set[]
205
+
206
+ 2.4.2 :028 > my_set = s💎[:hello, :world]
207
+ # => Persistent💎::Set[:hello, :world]
208
+ ----
209
+
210
+ === Converting from existing structures
211
+
212
+ You can use `💎ify[]` (or `dmndify[]`) to convert any received argument to a persistent structure (without modifying the original).
213
+ It is great for getting a protected copy of your input, that you can now store, operate on and share among threads without concern.
214
+
215
+ It works for all the persistent structures above:
216
+
217
+ [source,ruby]
218
+ ----
219
+ my_array = a💎[:hello, :world]
220
+ 💎ify[my_array]
221
+ # => Persistent💎::Array[:hello, :world]
222
+
223
+ my_hash = h💎['hello' => 'world']
224
+ 💎ify[my_hash]
225
+ # => Persistent💎::Hash["hello" => "world"]
226
+
227
+ my_set = s💎[:hello, :world]
228
+ 💎ify[my_set]
229
+ # => Persistent💎::Set[:hello, :world]
230
+ ----
231
+
232
+ It works for regular Ruby arrays (and any object that implements `to_ary()`):
233
+
234
+ [source,ruby]
235
+ ----
236
+ my_array = [:regular, :ruby, :array]
237
+ 💎ify[my_array]
238
+ # => Persistent💎::Array[:regular, :ruby, :array] # Not regular any more! :)
239
+ ----
240
+
241
+ It works for regular Ruby hashes (and any object that implements `to_hash()`):
242
+
243
+ [source,ruby]
244
+ ----
245
+ my_hash = {regular: :ruby, hash: nil}
246
+ 💎ify[my_hash]
247
+ # => Persistent💎::Hash[:hash => nil, :regular => :ruby]
248
+ ----
249
+
250
+ It works for regular Ruby sets (and any object that implements `to_set()`):
251
+
252
+ [source,ruby]
253
+ ----
254
+ my_set = Set.new([:regular, :ruby, :set])
255
+ 💎ify[my_set]
256
+ => Persistent💎::Set[:regular, :ruby, :set]
257
+ ----
258
+
259
+ And it works for https://github.com/hamstergem/hamster[hamster gem] (`Hamster::Vector`, `Hamster::Hash`, `Hamster::Set`) and https://github.com/ruby-concurrency/concurrent-ruby[concurrent-ruby gem] (`Concurrent::Array`, `Concurrent::Tuple`, `Concurrent::Hash`, `Concurrent::Map`) data structures:
260
+
261
+ [source,ruby]
262
+ ----
263
+ my_vector = Hamster::Vector[1, 2, 3]
264
+ 💎ify[my_vector]
265
+ # => Persistent💎::Array[1, 2, 3]
266
+
267
+ my_array = Concurrent::Array[1, 2, 3]
268
+ 💎ify[my_array]
269
+ # => Persistent💎::Array[1, 2, 3]
270
+
271
+ my_tuple = Concurrent::Tuple.new(1)
272
+ my_tuple.set(0, :hello)
273
+ 💎ify[my_tuple]
274
+ # => Persistent💎::Array[:hello]
275
+
276
+ my_hash = Hamster::Hash[hello: :world]
277
+ 💎ify[my_hash]
278
+ # => Persistent💎::Hash[:hello => :world]
279
+
280
+ my_hash = Concurrent::Hash[hello: :world]
281
+ 💎ify[my_hash]
282
+ # => Persistent💎::Hash[:hello => :world]
283
+
284
+ my_map = Concurrent::Map.new
285
+ my_map[:hello] = :world
286
+ 💎ify[my_map]
287
+ # => Persistent💎::Hash[:hello => :world]
288
+
289
+ my_set = Hamster::Set[:hello, :world]
290
+ 💎ify[my_set]
291
+ # => Persistent💎::Set[:hello, :world]
292
+ ----
293
+
294
+ And you can even implement it on your own classes:
295
+
296
+ [source,ruby]
297
+ ----
298
+ class MyList
299
+ include Persistent💎
300
+
301
+ def initialize(item1, item2, item3)
302
+ @item1 = item1
303
+ @item2 = item2
304
+ @item3 = item3
305
+ end
306
+
307
+ def to_💎 # can also be #to_dmnd
308
+ a💎[@item1, @item2, @item3]
309
+ end
310
+ end
311
+
312
+ my_list = MyList.new(:hello, :there, :readers)
313
+ 💎ify[my_list]
314
+ # => Persistent💎::Array[:hello, :there, :readers]
315
+ ----
316
+
317
+ === Converting to regular Ruby structures
318
+
319
+ The usual `to_a()`/`to_h()`/`to_set()` can be used to convert persistent data structures back to their regular Ruby counterparts:
320
+
321
+ [source,ruby]
322
+ ----
323
+ a💎[1, 2].to_a
324
+ # => [1, 2]
325
+
326
+ h💎[hello: :world].to_h
327
+ # => {:hello=>:world}
328
+
329
+ s💎[1, 2].to_set
330
+ # => #<Set: {1, 2}>
331
+ ----
332
+
333
+ === Converting between persistent structures
334
+
335
+ All three persistent structures implement `to_a💎()` (or `to_aDmnd()`), `to_h💎()` (or `to_hDmnd()`) and `to_s💎()` (or `to_sDmnd()`) as persistent counterparts for the usual Ruby `to_a()`, `to_h()` and `to_s()`:
336
+
337
+ [source,ruby]
338
+ ----
339
+ a💎[1, 2].to_a💎
340
+ # => Persistent💎::Array[1, 2]
341
+
342
+ a💎[1, 2].to_s💎
343
+ # => Persistent💎::Set[1, 2]
344
+
345
+ a💎[['hello', 'world']].to_h💎
346
+ # => Persistent💎::Hash["hello" => "world"]
347
+
348
+
349
+ h💎['hello' => 'world'].to_h💎
350
+ # => Persistent💎::Hash["hello" => "world"]
351
+
352
+ h💎['hello' => 'world'].to_a💎
353
+ # => Persistent💎::Array[Persistent💎::Array["hello", "world"]]
354
+
355
+ h💎['hello' => 'world'].to_s💎
356
+ # => Persistent💎::Set[Persistent💎::Array["hello", "world"]]
357
+
358
+
359
+ s💎[1, 2].to_s💎
360
+ # => Persistent💎::Set[1, 2]
361
+
362
+ s💎[1, 2].to_a💎
363
+ # => Persistent💎::Array[1, 2]
364
+
365
+ s💎[['hello', 'world']].to_h💎
366
+ # => Persistent💎::Hash["hello" => "world"]
367
+ ----
368
+
369
+ === Concurrent Ruby interoperability
370
+
371
+ When you need to go from thread-safe immutable data structures to thread-safe mutable data structures you can use Persistent-💎's _optional_ interoperability with the https://github.com/ruby-concurrency/concurrent-ruby[concurrent-ruby gem].
372
+
373
+ You'll need to install concurrent-ruby first, see https://github.com/ruby-concurrency/concurrent-ruby#installation for instructions.
374
+
375
+ After that, you'll be able to:
376
+
377
+ ==== Array
378
+
379
+ Use `to_concurrent()` (or `to_concurrent_array()`) to convert your array into a https://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Array.html[`Concurrent::Array`]:
380
+
381
+ [source,ruby]
382
+ ----
383
+ my_array = a💎[:hello, :world]
384
+ my_concurrent_array = my_array.to_concurrent
385
+ ----
386
+
387
+ Use `to_concurrent_tuple()` to convert your array into a https://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Tuple.html[`Concurrent::Tuple`]:
388
+
389
+ [source,ruby]
390
+ ----
391
+ my_array = a💎[:hello, :world]
392
+ my_concurrent_tuple = my_array.to_concurrent_tuple
393
+ # => #<Concurrent::Tuple @size=2, @tuple=[<#Concurrent::AtomicReference value:hello>, <#Concurrent::AtomicReference value:world>]>
394
+ ----
395
+
396
+ ==== Hash
397
+
398
+ Use `to_concurrent()` (or `to_concurrent_hash()`) to convert your hash into a https://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Hash.html[`Concurrent::Hash`]:
399
+
400
+ [source,ruby]
401
+ ----
402
+ my_hash = h💎[hello: :world]
403
+ my_concurrent_hash = my_hash.to_concurrent
404
+ ----
405
+
406
+ Use `to_concurrent_map()` to convert your hash into a https://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Map.html[`Concurrent::Map`]:
407
+
408
+ [source,ruby]
409
+ ----
410
+ my_hash = h💎[hello: :world]
411
+ my_concurrent_map = my_hash.to_concurrent_map
412
+ # => #<Concurrent::Map:0x0055ad9b283ea0 entries=1 default_proc=nil>
413
+ ----
414
+
415
+ === API documentation for the persistent structures
416
+
417
+ Because the persistent structures are provided by the awesome https://github.com/hamstergem/hamster[hamster gem], you can refer back to Hamster's API docs for details on the operations provided by each data structure.
418
+
419
+ ==== Array
420
+
421
+ Built on top of `Hamster::Vector`
422
+
423
+ * https://github.com/hamstergem/hamster#vector-api-documentation[Example usage]
424
+ * http://rubydoc.info/github/hamstergem/hamster/master/Hamster/Vector[API docs]
425
+
426
+ ==== Hash
427
+
428
+ Built on top of `Hamster::Hash`
429
+
430
+ * https://github.com/hamstergem/hamster#hash-api-documentation[Example usage]
431
+ * http://rubydoc.info/github/hamstergem/hamster/master/Hamster/Hash[API docs]
432
+
433
+ ==== Set
434
+
435
+ Built on top of `Hamster::Set`
436
+
437
+ * https://github.com/hamstergem/hamster#set-api-documentation[Example usage]
438
+ * http://www.rubydoc.info/github/hamstergem/hamster/master/Hamster/Set[API docs]
439
+
440
+ == AAARGH YOU FIEND WHY IS THERE AN EMOJI ON MY CODEBASE?
441
+
442
+ Every printable ascii character is already in use by Ruby, but I didn't want persistent data structures to clutter my source code. I also did not want to use cryptic single, two-letter or three-letter acronyms. Ruby is supposed to be beautifully readable!
443
+
444
+ Thus, I kept my Ruby beautiful. With two very clear characters you can create an immutable data structure. No more awkward typing of namespaces. No more `.freeze` everywhere. No-one will ever mistake the use of `💎` for another operation.
445
+
446
+ Now you can avoid having `💎` on your codebase altogether: just use `dmnd`, as <<usage,suggested above>>.
447
+
448
+ If you're having a hard time typing the emoji, I recommend just adding a quick snippet to your editor or a quick command to search-and-replace `aDmnd`/`hDmnd`/`sDmnd`/`dmndify` for `a💎`/`h💎`/`s💎`/`💎ify`. That way you get best of both worlds: easy to type, and easy to read!
449
+
450
+ == Usage on Ruby 1.9
451
+
452
+ Because of our usage of emojis for method names, you'll need to add
453
+
454
+ [source,ruby]
455
+ ----
456
+ # encoding: UTF-8
457
+ ----
458
+
459
+ as the first (or second) line of any file that uses Persistent-💎. As an alternative, you can also <<usage,use the `dmnd` syntax>>.
460
+
461
+ This setting is the default from Ruby 2.0 on, so users of later versions do not need to worry about this small detail.
462
+
463
+ == Development
464
+
465
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
466
+
467
+ To open a console with the gem loaded, run `bundle console`.
468
+
469
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to https://rubygems.org[rubygems.org].
470
+
471
+ == Contributing
472
+
473
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ivoanjo/persistent-dmnd.
474
+
475
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the http://contributor-covenant.org[Contributor Covenant] code of conduct.
476
+
477
+ Maintained with 💎❤️ by https://github.com/ivoanjo/[Ivo Anjo].
478
+
479
+ == Thanks
480
+
481
+ Thanks to these amazing people for their contributions!
482
+
483
+ * João Fernandes (https://github.com/jcmfernandes[@jcmfernandes])
484
+
485
+ == License
486
+
487
+ The gem is available as open source under the terms of the https://opensource.org/licenses/MIT[MIT License].
488
+
489
+ == Code of Conduct
490
+
491
+ Everyone interacting in the Persistent-💎 project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the https://github.com/ivoanjo/persistent-dmnd/blob/master/CODE_OF_CONDUCT.adoc[code of conduct].
492
+
493
+ == Interesting links
494
+
495
+ Interested in immutable/persistent data structures? Here are some interesting resources for your exploration:
496
+
497
+ * https://github.com/hamstergem/hamster[hamster gem]
498
+ * https://github.com/immutable-ruby/immutable-ruby[immmutable-ruby gem]
499
+ * https://github.com/ivoanjo/persistent-dmnd/issues[Your suggestion here]