destruct 0.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
+ SHA1:
3
+ metadata.gz: 8896e1df8a68ecfa8b0b885bd83e5854bfd5347b
4
+ data.tar.gz: a836c4d9a1029115f22dac0e02416eb1f3e17151
5
+ SHA512:
6
+ metadata.gz: 8bd49a04bb17c0c8552351a16cfe6e89496d29d88a1f049b7c4e4c77a8462957bbee426d762d356e87f8efad9b0dfc0188e15f10a967d14398886a946e806214
7
+ data.tar.gz: 1c1641c038067cf4b25c7157f7e7d2b575b868b641fb7e6822e22ae5192513efa5c52fa7f6158f5748f6accb8da37b884ac493566ed42f521a77c2f11744cab6
@@ -0,0 +1,9 @@
1
+ steps:
2
+ - name: ":rubocop:"
3
+ command: bin/rubocop
4
+ timeout_in_minutes: 30
5
+
6
+ - name: ":rspec:"
7
+ command: bin/test
8
+ timeout_in_minutes: 30
9
+ artifact_paths: cache.tar.lz4
@@ -0,0 +1,3 @@
1
+ coverage
2
+ pkg
3
+ rdoc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+ --require spec_helper
@@ -0,0 +1,2 @@
1
+ FROM lendinghome/rails
2
+ MAINTAINER github@lendinghome.com
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://www.rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "codeclimate-test-reporter"
6
+ gem "rspec"
@@ -0,0 +1,42 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ destruct (0.0.0)
5
+
6
+ GEM
7
+ remote: https://www.rubygems.org/
8
+ specs:
9
+ codeclimate-test-reporter (0.6.0)
10
+ simplecov (>= 0.7.1, < 1.0.0)
11
+ diff-lcs (1.2.5)
12
+ docile (1.1.5)
13
+ json (2.0.2)
14
+ rspec (3.5.0)
15
+ rspec-core (~> 3.5.0)
16
+ rspec-expectations (~> 3.5.0)
17
+ rspec-mocks (~> 3.5.0)
18
+ rspec-core (3.5.4)
19
+ rspec-support (~> 3.5.0)
20
+ rspec-expectations (3.5.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.5.0)
23
+ rspec-mocks (3.5.0)
24
+ diff-lcs (>= 1.2.0, < 2.0)
25
+ rspec-support (~> 3.5.0)
26
+ rspec-support (3.5.0)
27
+ simplecov (0.12.0)
28
+ docile (~> 1.1.0)
29
+ json (>= 1.8, < 3)
30
+ simplecov-html (~> 0.10.0)
31
+ simplecov-html (0.10.0)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ codeclimate-test-reporter
38
+ destruct!
39
+ rspec
40
+
41
+ BUNDLED WITH
42
+ 1.13.5
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 LendingHome - github@lendinghome.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,683 @@
1
+ # ![LendingHome](https://cloud.githubusercontent.com/assets/2419/19467866/7efa93a8-94c8-11e6-93e7-4375dbb8a7bc.png) destruct
2
+ [![Code Climate](https://codeclimate.com/github/LendingHome/destruct/badges/gpa.svg)](https://codeclimate.com/github/LendingHome/destruct) [![Coverage](https://codeclimate.com/github/LendingHome/destruct/badges/coverage.svg)](https://codeclimate.com/github/LendingHome/destruct) [![Gem Version](https://badge.fury.io/rb/destruct.svg)](http://badge.fury.io/rb/destruct)
3
+
4
+ > ES6 style object destructuring in Ruby
5
+
6
+ Check out the JavaScript [ES6 object destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) documentation for more information.
7
+
8
+ ## Why?
9
+
10
+ This was **primarily a learning exercise** to understand how this newer ES6 feature could work under the hood. We're not currently using this in production anywhere but it was a pretty fun challenge to solve.
11
+
12
+ ---
13
+
14
+ Ruby 2.3+ already has some built-in methods and operators for simple object destructuring:
15
+
16
+ * [`Array#dig`](http://ruby-doc.org/core-2.3.0/Array.html#method-i-dig)
17
+ * [`Hash#dig`](http://ruby-doc.org/core-2.3.0/Hash.html#method-i-dig)
18
+ * [`Struct#dig`](https://ruby-doc.org/core-2.3.0/Struct.html#method-i-dig)
19
+ * [`Array#values_at`](https://ruby-doc.org/core-2.3.0/Array.html#method-i-values_at)
20
+ * [`Hash#values_at`](https://ruby-doc.org/core-2.3.0/Hash.html#method-i-values_at)
21
+ * [Splat operator `*`](https://ruby-doc.org/core-2.3.0/doc/syntax/calling_methods_rdoc.html#label-Array+to+Arguments+Conversion)
22
+ * [Safe navigation operator `&.`](https://bugs.ruby-lang.org/issues/11537)
23
+
24
+ This gem introduces a couple of new methods to the `Object` class for more complex destructuring.
25
+
26
+ * `Object#dig`
27
+ * `Object#destruct`
28
+
29
+ It's mostly **useful for fetching multiple nested values out of objects** in a single method call.
30
+
31
+ ## Installation
32
+
33
+ Add this gem to the project `Gemfile`.
34
+
35
+ ```ruby
36
+ gem "destruct"
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ### `Object#dig`
42
+
43
+ This behaves just like the `dig` methods in `Array`, `Hash`, and `Struct` allowing ALL objects to be destructured.
44
+
45
+ The implementation simply uses `send` to pass valid method calls thru to objects recursively.
46
+
47
+ ```ruby
48
+ class Object
49
+ def dig(method, *paths)
50
+ object = send(method) if respond_to?(method)
51
+ paths.any? ? object&.dig(*paths) : object
52
+ end
53
+ end
54
+ ```
55
+
56
+ This method behaves very similar to the safe navigation operator `&.` but checks if the object responds to the method before attempting to call it. Invalid method calls return `nil` instead of raising `NoMethodError`.
57
+
58
+ ```ruby
59
+ "test".dig(:upcase, :reverse) # "TSET"
60
+ "test".dig(:invalid, :chain, :of, :methods) # nil
61
+ ```
62
+
63
+ It also delegates to native `dig` implementations for `Array`, `Hash`, or `Struct` objects whenever possible.
64
+
65
+ ```ruby
66
+ class Blog
67
+ def posts
68
+ [
69
+ { "title" => "Testing" },
70
+ { "title" => "Example" }
71
+ ]
72
+ end
73
+ end
74
+
75
+ Blog.new.dig(:posts, 1, "title") # "Example"
76
+ ```
77
+
78
+ ### `Object#destruct`
79
+
80
+ This method is like a hybrid of all the other native Ruby destructuring methods! Let's define an example object:
81
+
82
+ ```ruby
83
+ object = {
84
+ id: 123,
85
+ title: "Hi",
86
+ translations: [
87
+ {
88
+ locale: "es_MX",
89
+ last_edit: "2014-04-14T08:43:37",
90
+ title: "Hola"
91
+ }
92
+ ],
93
+ url: "/hi-123"
94
+ }
95
+ ```
96
+
97
+ It behaves like `values_at` and looks up values by keys:
98
+
99
+ ```ruby
100
+ id, url = object.destruct(:id, :url)
101
+ puts id # 123
102
+ puts url # "/hi-123"
103
+ ```
104
+
105
+ It behaves like `dig` to lookup nested values:
106
+
107
+ ```ruby
108
+ title, locale_title = object.destruct(:title, [:translations, 0, :title])
109
+ puts title # "Hi"
110
+ puts locale_title # "Hola"
111
+ ```
112
+
113
+ It accepts hashes to `dig` out nested values as well:
114
+
115
+ ```ruby
116
+ locale, title = object.destruct(translations: { 0 => [:locale, :title] })
117
+ puts locale # "es_MX"
118
+ puts title # "Hola"
119
+ ```
120
+
121
+ It accepts a mixture of different argument types:
122
+
123
+ ```ruby
124
+ title, last_edit, locale, locale_title = object.destruct(
125
+ :title,
126
+ [:translations, 0, :last_edit],
127
+ translations: { 0 => [:locale, :title] }
128
+ )
129
+
130
+ puts title # "Hi"
131
+ puts last_edit # "2014-04-14T08:43:37"
132
+ puts locale # "es_MX"
133
+ puts locale_title # "Hola"
134
+ ```
135
+
136
+ It accepts a block to lookup nested values with a clear and convenient DSL:
137
+
138
+ ```ruby
139
+ title, last_edit, locale, url = object.destruct do
140
+ title
141
+ translations[0].last_edit
142
+ translations[0][:locale]
143
+ url
144
+ end
145
+
146
+ puts title # "Hi"
147
+ puts last_edit # "2014-04-14T08:43:37"
148
+ puts locale # "es_MX"
149
+ puts url # "/hi-123"
150
+ ```
151
+
152
+ It returns a `Destruct::Hash` object when the return values are not splatted:
153
+
154
+ ```ruby
155
+ destructured = object.destruct do
156
+ title
157
+ translations[0].last_edit
158
+ translations[0][:locale]
159
+ url
160
+ end
161
+
162
+ puts destructured.title # "Hi"
163
+ puts destructured[:title] # "Hi"
164
+ puts destructured[0] # "Hi"
165
+
166
+ puts destructured.last_edit # "2014-04-14T08:43:37"
167
+ puts destructured.locale # "es_MX"
168
+
169
+ puts destructured.url # "/hi-123"
170
+ puts destructured[-1] # "/hi-123"
171
+
172
+ puts destructured[999] # nil
173
+ puts destructured[:missing] # nil
174
+ puts destructured.missing # NoMethodError
175
+ ```
176
+
177
+ Note that `Destruct::Hash` values are overwritten if there are multiple with the same keys:
178
+
179
+ ```ruby
180
+ destructured = object.destruct(:title, [:translations, 0, :title])
181
+
182
+ puts destructured.title # "Hola"
183
+
184
+ # This is where the index lookups really come in handy
185
+ puts destructured[0] # "Hi"
186
+ puts destructured[1] # "Hola"
187
+ ```
188
+
189
+ The return value destructuring is done using `Destruct::Hash#to_ary` for implicit `Array` conversion!
190
+
191
+ ## Examples
192
+
193
+ Let's compare some of the JavaScript [ES6 destructuring examples](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) with their Ruby equivalents.
194
+
195
+ Note that almost all of these examples simply use native Ruby 2.3+ features!
196
+
197
+ ### Array destructuring
198
+
199
+ #### Basic variable assignment
200
+
201
+ ```javascript
202
+ var foo = ["one", "two", "three"];
203
+ var [one, two, three] = foo;
204
+
205
+ console.log(one); // "one"
206
+ console.log(two); // "two"
207
+ console.log(three); // "three"
208
+ ```
209
+
210
+ ```ruby
211
+ foo = ["one", "two", "three"]
212
+ one, two, three = foo
213
+
214
+ puts one # "one"
215
+ puts two # "two"
216
+ puts three # "three"
217
+ ```
218
+
219
+ #### Default values
220
+
221
+ ```javascript
222
+ var [a=5, b=7] = [1];
223
+
224
+ console.log(a); // 1
225
+ console.log(b); // 7
226
+ ```
227
+
228
+ ```ruby
229
+ a, b = [1]
230
+ a ||= 5
231
+ b ||= 7
232
+
233
+ puts a # 1
234
+ puts b # 7
235
+ ```
236
+
237
+ #### Swapping variables
238
+
239
+ ```javascript
240
+ var a = 1;
241
+ var b = 3;
242
+ [a, b] = [b, a];
243
+
244
+ console.log(a); // 3
245
+ console.log(b); // 1
246
+ ```
247
+
248
+ ```ruby
249
+ a = 1
250
+ b = 3
251
+ a, b = b, a
252
+
253
+ puts a # 3
254
+ puts b # 1
255
+ ```
256
+
257
+ #### Parsing an array returned from a function
258
+
259
+ ```javascript
260
+ function f() {
261
+ return [1, 2];
262
+ }
263
+
264
+ var [a, b] = f();
265
+
266
+ console.log(a); // 1
267
+ console.log(b); // 2
268
+ ```
269
+
270
+ ```ruby
271
+ def f
272
+ [1, 2]
273
+ end
274
+
275
+ a, b = f
276
+
277
+ puts a # 1
278
+ puts b # 2
279
+ ```
280
+
281
+ #### Ignoring some returned values
282
+
283
+ ```javascript
284
+ function f() {
285
+ return [1, 2, 3];
286
+ }
287
+
288
+ var [a, , b] = f();
289
+
290
+ console.log(a); // 1
291
+ console.log(b); // 3
292
+ ```
293
+
294
+ ```ruby
295
+ def f
296
+ [1, 2, 3]
297
+ end
298
+
299
+ a, _, b = f
300
+
301
+ puts a # 1
302
+ puts b # 3
303
+ ```
304
+
305
+ #### Ignoring remaining values
306
+
307
+ ```javascript
308
+ var [a, b] = [1, 2, 3, 4];
309
+
310
+ console.log(a); // 1
311
+ console.log(b); // 2
312
+ ```
313
+
314
+ ```ruby
315
+ a, b = [1, 2, 3, 4]
316
+
317
+ puts a # 1
318
+ puts b # 2
319
+ ```
320
+
321
+ #### Capture remaining values
322
+
323
+ ```javascript
324
+ var [a, b, ...c] = [1, 2, 3, 4];
325
+
326
+ console.log(c); // [3, 4]
327
+ ```
328
+
329
+ ```ruby
330
+ a, b, *c = [1, 2, 3, 4]
331
+
332
+ puts c.inspect # [3, 4]
333
+ ```
334
+
335
+ #### Destructure a nested array
336
+
337
+ ```javascript
338
+ const avengers = [
339
+ "Natasha Romanoff",
340
+ ["Tony Stark", "James Rhodes"],
341
+ ["Steve Rogers", "Sam Wilson"]
342
+ ];
343
+
344
+ const [blackWidow, [ironMan, warMachine], [cap, falcon]] = avengers;
345
+
346
+ console.log(warMachine); // "James Rhodes"
347
+ ```
348
+
349
+ ```ruby
350
+ avengers = [
351
+ "Natasha Romanoff",
352
+ ["Tony Stark", "James Rhodes"],
353
+ ["Steve Rogers", "Sam Wilson"]
354
+ ]
355
+
356
+ black_widow, iron_man, war_machine, cap, falcon = avengers.flatten
357
+
358
+ puts war_machine # "James Rhodes"
359
+ ```
360
+
361
+ #### Pluck a single value from a deeply nested array
362
+
363
+ ```javascript
364
+ const avengers = [
365
+ "Natasha Romanoff",
366
+ [["Tony Stark", "Pepper Potts"], "James Rhodes"],
367
+ ["Steve Rogers", "Sam Wilson"]
368
+ ];
369
+
370
+ const [, [[, potts ]]] = avengers;
371
+
372
+ console.log(potts); // "Pepper Potts"
373
+ ```
374
+
375
+ ```ruby
376
+ avengers = [
377
+ "Natasha Romanoff",
378
+ [["Tony Stark", "Pepper Potts"], "James Rhodes"],
379
+ ["Steve Rogers", "Sam Wilson"]
380
+ ]
381
+
382
+ potts = avengers.dig(1, 0, 1)
383
+
384
+ puts potts # "Pepper Potts"
385
+ ```
386
+
387
+ #### Pulling values from a regular expression match
388
+
389
+ ```javascript
390
+ var url = "https://developer.mozilla.org/en-US/Web/JavaScript";
391
+
392
+ var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
393
+ console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]
394
+
395
+ var [, protocol, fullhost, fullpath] = parsedURL;
396
+ console.log(protocol); // "https"
397
+ ```
398
+
399
+ ```ruby
400
+ url = "https://developer.mozilla.org/en-US/Web/JavaScript"
401
+
402
+ parsed_url = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.match(url).to_a
403
+ puts parsed_url.inspect # ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]
404
+
405
+ _, protocol, fullhost, fullpath = parsed_url.to_a
406
+ puts protocol # "https"
407
+ ```
408
+
409
+ ### Object destructuring
410
+
411
+ #### Basic assignment
412
+
413
+ ```javascript
414
+ var o = {p: 42, q: true};
415
+ var {p, q} = o;
416
+
417
+ console.log(p); // 42
418
+ console.log(q); // true
419
+ ```
420
+
421
+ ```ruby
422
+ o = { p: 42, q: true }
423
+ p, q = o.values_at(:p, :q)
424
+
425
+ puts p # 42
426
+ puts q # true
427
+ ```
428
+
429
+ #### Assigning to new variable names
430
+
431
+ ```javascript
432
+ var o = {p: 42, q: true};
433
+ var {p: foo, q: bar} = o;
434
+
435
+ console.log(foo); // 42
436
+ console.log(bar); // true
437
+ ```
438
+
439
+ ```ruby
440
+ o = { p: 42, q: true }
441
+ foo, bar = o.values_at(:p, :q)
442
+
443
+ puts foo # 42
444
+ puts bar # true
445
+ ```
446
+
447
+ #### Default values
448
+
449
+ ```javascript
450
+ var {a=10, b=5} = {a: 3};
451
+
452
+ console.log(a); // 3
453
+ console.log(b); // 5
454
+ ```
455
+
456
+ ```ruby
457
+ a, b = { a: 3 }.values_at(:a, :b)
458
+ a ||= 10
459
+ b ||= 5
460
+
461
+ puts a # 3
462
+ puts b # 5
463
+ ```
464
+
465
+ #### Setting default function parameters
466
+
467
+ ```javascript
468
+ function drawES6Chart({size = "big", cords = { x: 0, y: 0 }, radius = 25} = {}) {
469
+ console.log(size, cords, radius);
470
+ // do some chart drawing
471
+ }
472
+
473
+ drawES6Chart({
474
+ cords: { x: 18, y: 30 },
475
+ radius: 30
476
+ });
477
+ ```
478
+
479
+ ```ruby
480
+ def draw_es6_chart(size: "big", cords: { x: 0, y: 0 }, radius: 25)
481
+ puts size, cords, radius
482
+ # do some chart drawing
483
+ end
484
+
485
+ draw_es6_chart(
486
+ cords: { x: 18, y: 30 },
487
+ radius: 30
488
+ )
489
+ ```
490
+
491
+ #### Nested object and array destructuring
492
+
493
+ ```javascript
494
+ var metadata = {
495
+ title: "Scratchpad",
496
+ translations: [
497
+ {
498
+ locale: "de",
499
+ localization_tags: [ ],
500
+ last_edit: "2014-04-14T08:43:37",
501
+ url: "/de/docs/Tools/Scratchpad",
502
+ title: "JavaScript-Umgebung"
503
+ }
504
+ ],
505
+ url: "/en-US/docs/Tools/Scratchpad"
506
+ };
507
+
508
+ var { title: englishTitle, translations: [{ title: localeTitle }] } = metadata;
509
+
510
+ console.log(englishTitle); // "Scratchpad"
511
+ console.log(localeTitle); // "JavaScript-Umgebung"
512
+ ```
513
+
514
+ ```ruby
515
+ metadata = {
516
+ title: "Scratchpad",
517
+ translations: [
518
+ {
519
+ locale: "de",
520
+ localization_tags: [ ],
521
+ last_edit: "2014-04-14T08:43:37",
522
+ url: "/de/docs/Tools/Scratchpad",
523
+ title: "JavaScript-Umgebung"
524
+ }
525
+ ],
526
+ url: "/en-US/docs/Tools/Scratchpad"
527
+ }
528
+
529
+ english_title, locale_title = metadata.destruct do
530
+ title
531
+ translations[0].title
532
+ end
533
+
534
+ puts english_title # "Scratchpad"
535
+ puts locale_title # "JavaScript-Umgebung"
536
+ ```
537
+
538
+ #### For of iteration and destructuring
539
+
540
+ ```javascript
541
+ var people = [
542
+ {
543
+ name: "Mike Smith",
544
+ family: {
545
+ mother: "Jane Smith",
546
+ father: "Harry Smith",
547
+ sister: "Samantha Smith"
548
+ },
549
+ age: 35
550
+ },
551
+ {
552
+ name: "Tom Jones",
553
+ family: {
554
+ mother: "Norah Jones",
555
+ father: "Richard Jones",
556
+ brother: "Howard Jones"
557
+ },
558
+ age: 25
559
+ }
560
+ ];
561
+
562
+ for (var {name: n, family: { father: f } } of people) {
563
+ console.log("Name: " + n + ", Father: " + f);
564
+ }
565
+
566
+ // "Name: Mike Smith, Father: Harry Smith"
567
+ // "Name: Tom Jones, Father: Richard Jones"
568
+ ```
569
+
570
+ ```ruby
571
+ people = [
572
+ {
573
+ name: "Mike Smith",
574
+ family: {
575
+ mother: "Jane Smith",
576
+ father: "Harry Smith",
577
+ sister: "Samantha Smith"
578
+ },
579
+ age: 35
580
+ },
581
+ {
582
+ name: "Tom Jones",
583
+ family: {
584
+ mother: "Norah Jones",
585
+ father: "Richard Jones",
586
+ brother: "Howard Jones"
587
+ },
588
+ age: 25
589
+ }
590
+ ]
591
+
592
+ people.each do |person|
593
+ n, f = person.destruct(:name, family: :father)
594
+ puts "Name: #{n}, Father: #{f}"
595
+ end
596
+
597
+ # "Name: Mike Smith, Father: Harry Smith"
598
+ # "Name: Tom Jones, Father: Richard Jones"
599
+ ```
600
+
601
+ #### Pulling fields from objects passed as function parameter
602
+
603
+ ```javascript
604
+ function userId({id}) {
605
+ return id;
606
+ }
607
+
608
+ function whois({displayName: displayName, fullName: {firstName: name}}){
609
+ console.log(displayName + " is " + name);
610
+ }
611
+
612
+ var user = {
613
+ id: 42,
614
+ displayName: "jdoe",
615
+ fullName: {
616
+ firstName: "John",
617
+ lastName: "Doe"
618
+ }
619
+ };
620
+
621
+ console.log("userId: " + userId(user)); // "userId: 42"
622
+ whois(user); // "jdoe is John"
623
+ ```
624
+
625
+ ```ruby
626
+ def user_id(id:)
627
+ id
628
+ end
629
+
630
+ def whois(display_name:, full_name:)
631
+ puts "#{display_name} is #{full_name[:first_name]}"
632
+ end
633
+
634
+ user = {
635
+ id: 42,
636
+ displayName: "jdoe",
637
+ fullName: {
638
+ firstName: "John",
639
+ lastName: "Doe"
640
+ }
641
+ }
642
+
643
+ puts "userId: #{user_id(user)}" # "userId: 42"
644
+ whois(user) # "jdoe is John"
645
+ ```
646
+
647
+ #### Computed object property names
648
+
649
+ ```javascript
650
+ let key = "z";
651
+ let { [key]: foo } = { z: "bar" };
652
+
653
+ console.log(foo); // "bar"
654
+ ```
655
+
656
+ ```ruby
657
+ key = :z
658
+ foo = { z: "bar" }[key]
659
+
660
+ puts foo # "bar"
661
+ ```
662
+
663
+ ## Testing
664
+
665
+ ```bash
666
+ bundle exec rspec
667
+ ```
668
+
669
+ ## Contributing
670
+
671
+ * Fork the project.
672
+ * Make your feature addition or bug fix.
673
+ * Add tests for it. This is important so we don't break it in a future version unintentionally.
674
+ * Commit, do not mess with the version or history.
675
+ * Open a pull request. Bonus points for topic branches.
676
+
677
+ ## Authors
678
+
679
+ * [Sean Huber](https://github.com/shuber)
680
+
681
+ ## License
682
+
683
+ [MIT](https://github.com/lendinghome/destruct/blob/master/LICENSE) - Copyright © 2016 LendingHome