blueprinter 0.25.3 → 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,23 +1,38 @@
1
- [![CircleCI](https://circleci.com/gh/procore/blueprinter.svg?style=svg)](https://circleci.com/gh/procore/blueprinter)
1
+ [![Test](https://github.com/procore-oss/blueprinter/actions/workflows/test.yaml/badge.svg?branch=master)](https://github.com/procore-oss/blueprinter/actions/workflows/test.yaml)
2
2
  [![Gem Version](https://badge.fury.io/rb/blueprinter.svg)](https://badge.fury.io/rb/blueprinter)
3
3
  [![Gitter chat](https://badges.gitter.im/procore/blueprinter.svg)](https://gitter.im/blueprinter-gem/community)
4
4
 
5
5
  <img src="blueprinter_logo.svg" width="25%">
6
6
 
7
+ # Recent Organization Move
8
+
9
+ Please change your local remote to pull from this repository:
10
+
11
+ ```bash
12
+ git remote set-url [previous-remote-name] git@github.com:procore-oss/blueprinter.git
13
+ ```
14
+
15
+ to see the previous upstream remote name, run:
16
+
17
+ ```bash
18
+ git remote -v
19
+ ```
20
+
7
21
  # Blueprinter
22
+
8
23
  Blueprinter is a JSON Object Presenter for Ruby that takes business objects and breaks them down into simple hashes and serializes them to JSON. It can be used in Rails in place of other serializers (like JBuilder or ActiveModelSerializers). It is designed to be simple, direct, and performant.
9
24
 
10
25
  It heavily relies on the idea of `views` which, similar to Rails views, are ways of predefining output for data in different contexts.
11
26
 
12
27
  ## Documentation
28
+
13
29
  Docs can be found [here](http://www.rubydoc.info/gems/blueprinter).
14
30
 
15
31
  ## Usage
32
+
16
33
  <details open>
17
34
  <summary>Basic</summary>
18
35
 
19
- ---
20
-
21
36
  If you have an object you would like serialized, simply create a blueprint. Say, for example, you have a User record with the following attributes `[:uuid, :email, :first_name, :last_name, :password, :address]`.
22
37
 
23
38
  You may define a simple blueprint like so:
@@ -31,6 +46,7 @@ end
31
46
  ```
32
47
 
33
48
  and then, in your code:
49
+
34
50
  ```ruby
35
51
  puts UserBlueprint.render(user) # Output is a JSON string
36
52
  ```
@@ -45,15 +61,11 @@ And the output would look like:
45
61
  "last_name": "Doe"
46
62
  }
47
63
  ```
48
-
49
- ---
50
64
  </details>
51
65
 
52
-
53
66
  <details>
54
67
  <summary>Collections</summary>
55
68
 
56
- ---
57
69
 
58
70
  You can also pass a collection object or an array to the render method.
59
71
 
@@ -80,14 +92,28 @@ This will result in JSON that looks something like this:
80
92
  ]
81
93
  ```
82
94
 
83
- ---
84
- </details>
85
95
 
96
+ You can also configure other classes to be treated like collections. For example, if you are using Mongoid, you can configure it to treat `Mongoid::Criteria` objects as collections:
97
+
98
+ ```ruby
99
+ Blueprinter.configure do |config|
100
+ config.custom_array_like_classes = [Mongoid::Criteria]
101
+ end
102
+ ```
103
+
104
+ Or if you wanted it to treat the `Set` class as a collection:
105
+
106
+ ```ruby
107
+ Blueprinter.configure do |config|
108
+ config.custom_array_like_classes = [Set]
109
+ end
110
+ ```
111
+
112
+ </details>
86
113
 
87
114
  <details>
88
115
  <summary>Renaming</summary>
89
116
 
90
- ---
91
117
 
92
118
  You can rename the resulting JSON keys in both fields and associations by using the `name` option.
93
119
 
@@ -111,16 +137,14 @@ This will result in JSON that looks something like this:
111
137
  }
112
138
  ```
113
139
 
114
- ---
115
140
  </details>
116
141
 
117
-
118
142
  <details>
119
143
  <summary>Views</summary>
120
144
 
121
- ---
122
145
 
123
146
  You may define different outputs by utilizing views:
147
+
124
148
  ```ruby
125
149
  class UserBlueprint < Blueprinter::Base
126
150
  identifier :uuid
@@ -137,14 +161,17 @@ class UserBlueprint < Blueprinter::Base
137
161
  end
138
162
  end
139
163
  ```
164
+
140
165
  A view can include fields from another view by utilizing `include_view` and `include_views`.
141
166
 
142
167
  Usage:
168
+
143
169
  ```ruby
144
170
  puts UserBlueprint.render(user, view: :extended)
145
171
  ```
146
172
 
147
173
  Output:
174
+
148
175
  ```json
149
176
  {
150
177
  "uuid": "733f0758-8f21-4719-875f-262c3ec743af",
@@ -155,16 +182,38 @@ Output:
155
182
  }
156
183
  ```
157
184
 
158
- ---
159
185
  </details>
160
186
 
187
+ <details>
188
+ <summary>Identifiers</summary>
189
+
190
+
191
+ `identifier`s are used to specify a field or method name used as an identifier. Usually, this is something like `:id`.
192
+
193
+ Example:
194
+
195
+ ```rb
196
+ class UserBlueprint < Blueprinter::Base
197
+ identifier :uuid
198
+ end
199
+ ```
200
+
201
+ Blueprinter `identifier`s have a few properties that set them apart from `field`s.
202
+
203
+ 1. Identifiers are **always** rendered and considered their own view (the `:identifier` view).
204
+ 2. When rendering, identifier fields are always sorted first, before other fields.
205
+
206
+ If either of the above two developer conveniences are not desired, you can simply create your identifier fields as regular `field`s.
207
+
208
+
209
+ </details>
161
210
 
162
211
  <details>
163
212
  <summary>Root</summary>
164
-
165
- ---
213
+ <a name="root"></a>
166
214
 
167
215
  You can also optionally pass in a root key to wrap your resulting json in:
216
+
168
217
  ```ruby
169
218
  class UserBlueprint < Blueprinter::Base
170
219
  identifier :uuid
@@ -177,11 +226,13 @@ end
177
226
  ```
178
227
 
179
228
  Usage:
229
+
180
230
  ```ruby
181
231
  puts UserBlueprint.render(user, view: :normal, root: :user)
182
232
  ```
183
233
 
184
234
  Output:
235
+
185
236
  ```json
186
237
  {
187
238
  "user": {
@@ -193,16 +244,14 @@ Output:
193
244
  }
194
245
  ```
195
246
 
196
- ---
197
247
  </details>
198
248
 
199
-
200
249
  <details>
201
250
  <summary>Meta Attributes</summary>
202
251
 
203
- ---
204
252
 
205
253
  You can additionally add meta-data to the json as well:
254
+
206
255
  ```ruby
207
256
  class UserBlueprint < Blueprinter::Base
208
257
  identifier :uuid
@@ -215,6 +264,7 @@ end
215
264
  ```
216
265
 
217
266
  Usage:
267
+
218
268
  ```ruby
219
269
  json = UserBlueprint.render(user, view: :normal, root: :user, meta: {links: [
220
270
  'https://app.mydomain.com',
@@ -224,6 +274,7 @@ puts json
224
274
  ```
225
275
 
226
276
  Output:
277
+
227
278
  ```json
228
279
  {
229
280
  "user": {
@@ -240,18 +291,17 @@ Output:
240
291
  }
241
292
  }
242
293
  ```
294
+
243
295
  _NOTE:_ For meta attributes, a [root](#root) is mandatory.
244
296
 
245
- ---
246
297
  </details>
247
298
 
248
-
249
299
  <details>
250
300
  <summary>Exclude Fields</summary>
251
301
 
252
- ---
253
302
 
254
303
  You can specifically choose to exclude certain fields for specific views
304
+
255
305
  ```ruby
256
306
  class UserBlueprint < Blueprinter::Base
257
307
  identifier :uuid
@@ -270,11 +320,13 @@ end
270
320
  ```
271
321
 
272
322
  Usage:
323
+
273
324
  ```ruby
274
325
  puts UserBlueprint.render(user, view: :extended)
275
326
  ```
276
327
 
277
328
  Output:
329
+
278
330
  ```json
279
331
  {
280
332
  "uuid": "733f0758-8f21-4719-875f-262c3ec743af",
@@ -303,16 +355,14 @@ class UserBlueprint < Blueprinter::Base
303
355
  end
304
356
  ```
305
357
 
306
- ---
307
358
  </details>
308
359
 
309
-
310
360
  <details>
311
361
  <summary>Associations</summary>
312
362
 
313
- ---
314
363
 
315
364
  You may include associated objects. Say for example, a user has projects:
365
+
316
366
  ```ruby
317
367
  class ProjectBlueprint < Blueprinter::Base
318
368
  identifier :uuid
@@ -331,11 +381,13 @@ end
331
381
  ```
332
382
 
333
383
  Usage:
384
+
334
385
  ```ruby
335
386
  puts UserBlueprint.render(user, view: :normal)
336
387
  ```
337
388
 
338
389
  Output:
390
+
339
391
  ```json
340
392
  {
341
393
  "uuid": "733f0758-8f21-4719-875f-262c3ec743af",
@@ -357,6 +409,7 @@ Output:
357
409
 
358
410
  It is also possible to pass options from one Blueprint to another via an association.
359
411
  For example:
412
+
360
413
  ```ruby
361
414
  class VehicleBlueprint < Blueprinter::Base
362
415
  identifier :uuid
@@ -375,18 +428,16 @@ class DriverBlueprint < Blueprinter::Base
375
428
  end
376
429
  ```
377
430
 
378
- ---
379
431
  </details>
380
432
 
381
-
382
433
  <details>
383
434
  <summary>Default Association/Field Option</summary>
384
435
 
385
- ---
386
436
 
387
437
  By default, an association or field that evaluates to `nil` is serialized as `nil`. A default serialized value can be specified as an option on the association or field for cases when the association/field could potentially evaluate to `nil`. You can also specify a global `field_default` or `association_default` in the Blueprinter config which will be used for all fields/associations that evaluate to nil.
388
438
 
389
- #### Global Config Setting
439
+ ### Global Config Setting
440
+
390
441
  ```ruby
391
442
  Blueprinter.configure do |config|
392
443
  config.field_default = "N/A"
@@ -394,7 +445,8 @@ Blueprinter.configure do |config|
394
445
  end
395
446
  ```
396
447
 
397
- #### Field-level/Association-level Setting
448
+ ### Field-level/Association-level Setting
449
+
398
450
  ```ruby
399
451
  class UserBlueprint < Blueprinter::Base
400
452
  identifier :uuid
@@ -406,51 +458,50 @@ class UserBlueprint < Blueprinter::Base
406
458
  end
407
459
  ```
408
460
 
409
- ---
410
461
  </details>
411
462
 
412
-
413
463
  <details>
414
464
  <summary>default_if</summary>
415
465
 
416
- ---
417
466
 
418
467
  Sometimes, you may want certain "empty" values to pass through to the default value.
419
468
  Blueprinter provides the ability to treat the following empty types as the default value (or `nil` if no default provided).
420
469
 
421
- #### Blueprinter::EMPTY_COLLECTION
470
+ ### Blueprinter::EMPTY_COLLECTION
471
+
422
472
  An empty array or empty active record collection.
423
473
 
424
- #### Blueprinter::EMPTY_HASH
474
+ ### Blueprinter::EMPTY_HASH
475
+
425
476
  An empty hash.
426
477
 
427
- #### Blueprinter::EMPTY_STRING
478
+ ### Blueprinter::EMPTY_STRING
479
+
428
480
  An empty string or symbol.
429
481
 
430
- #### Field-level/Association-level Setting
482
+ #### Field-level/Association-level Setting - EMPTY_STRING
483
+
431
484
  ```ruby
432
485
  class UserBlueprint < Blueprinter::Base
433
486
  identifier :uuid
434
487
 
435
488
  view :normal do
436
489
  # If first_name is an empty string, it will become "N/A"
437
- field :first_name, default_if: Blueprinter::EmptyString, default: "N/A"
490
+ field :first_name, default_if: Blueprinter::EMPTY_STRING, default: "N/A"
438
491
  # If the projects association collection is empty, it will become nil
439
- association :projects, blueprint: ProjectBlueprint, default_if: Blueprinter::EmptyCollection
492
+ association :projects, blueprint: ProjectBlueprint, default_if: Blueprinter::EMPTY_COLLECTION
440
493
  end
441
494
  end
442
495
  ```
443
496
 
444
- ---
445
497
  </details>
446
498
 
447
-
448
499
  <details>
449
500
  <summary>Supporting Dynamic Blueprints For Associations</summary>
450
501
 
451
- ---
452
502
 
453
503
  When defining an association, we can dynamically evaluate the blueprint. This comes in handy when adding polymorphic associations, by allowing reuse of existing blueprints.
504
+
454
505
  ```ruby
455
506
  class Task < ActiveRecord::Base
456
507
  belongs_to :taskable, polymorphic: true
@@ -473,16 +524,14 @@ class TaskBlueprint < Blueprinter::Base
473
524
  end
474
525
  end
475
526
  ```
527
+
476
528
  _NOTE:_ `taskable.blueprint` should return a valid Blueprint class. Currently, `has_many` is not supported because of the very nature of polymorphic associations.
477
529
 
478
- ---
479
530
  </details>
480
531
 
481
-
482
532
  <details>
483
533
  <summary>Defining A Field Directly In The Blueprint</summary>
484
534
 
485
- ---
486
535
 
487
536
  You can define a field directly in the Blueprint by passing it a block. This is especially useful if the object does not already have such an attribute or method defined, and you want to define it specifically for use with the Blueprint. This is done by passing `field` a block. The block also yields the object and any options that were passed from `render`. For example:
488
537
 
@@ -510,14 +559,11 @@ Output:
510
559
  }
511
560
  ```
512
561
 
513
- ---
514
562
  </details>
515
563
 
516
-
517
564
  <details>
518
565
  <summary>Defining An Identifier Directly In The Blueprint</summary>
519
566
 
520
- ---
521
567
 
522
568
  You can also pass a block to an identifier:
523
569
 
@@ -543,14 +589,11 @@ Output:
543
589
  }
544
590
  ```
545
591
 
546
- ---
547
592
  </details>
548
593
 
549
-
550
594
  <details>
551
595
  <summary>Defining An Association Directly In The Blueprint</summary>
552
596
 
553
- ---
554
597
 
555
598
  You can also pass a block to an association:
556
599
 
@@ -588,14 +631,11 @@ Output:
588
631
  }
589
632
  ```
590
633
 
591
- ---
592
634
  </details>
593
635
 
594
-
595
636
  <details>
596
637
  <summary>Passing Additional Properties To #render</summary>
597
638
 
598
- ---
599
639
 
600
640
  `render` takes an options hash which you can pass additional properties, allowing you to utilize those additional properties in the `field` block. For example:
601
641
 
@@ -623,18 +663,16 @@ Output:
623
663
  }
624
664
  ```
625
665
 
626
- ---
627
666
  </details>
628
667
 
629
-
630
668
  <details>
631
669
  <summary>Conditional Fields</summary>
632
670
 
633
- ---
634
671
 
635
672
  Both the `field` and the global Blueprinter Configuration supports `:if` and `:unless` options that can be used to serialize fields conditionally.
636
673
 
637
- #### Global Config Setting
674
+ ### Global Config Setting - if and unless
675
+
638
676
  ```ruby
639
677
  Blueprinter.configure do |config|
640
678
  config.if = ->(field_name, obj, _options) { !obj[field_name].nil? }
@@ -643,6 +681,7 @@ end
643
681
  ```
644
682
 
645
683
  #### Field-level Setting
684
+
646
685
  ```ruby
647
686
  class UserBlueprint < Blueprinter::Base
648
687
  identifier :uuid
@@ -653,32 +692,32 @@ end
653
692
 
654
693
  _NOTE:_ The field-level setting overrides the global config setting (for the field) if both are set.
655
694
 
656
- ---
657
695
  </details>
658
696
 
659
-
660
697
  <details>
661
698
  <summary>Custom Formatting for Dates and Times</summary>
662
699
 
663
- ---
664
700
 
665
701
  To define a custom format for a Date or DateTime field, include the option `datetime_format`.
666
702
  This global or field-level option can be either a string representing the associated `strftime` format,
667
703
  or a Proc which receives the original Date/DateTime object and returns the formatted value.
668
704
  When using a Proc, it is the Proc's responsibility to handle any errors in formatting.
669
705
 
706
+ #### Global Config Setting - datetime
670
707
 
671
- #### Global Config Setting
672
708
  If a global datetime_format is set (either as a string format or a Proc), this option will be
673
709
  invoked and used to format all fields that respond to `strftime`.
710
+
674
711
  ```ruby
675
712
  Blueprinter.configure do |config|
676
713
  config.datetime_format = ->(datetime) { datetime.nil? ? datetime : datetime.strftime("%s").to_i }
677
714
  end
678
715
  ```
679
716
 
680
- #### Field-level Setting
717
+ #### Field-level Setting - datetime_format
718
+
681
719
  Usage (String Option):
720
+
682
721
  ```ruby
683
722
  class UserBlueprint < Blueprinter::Base
684
723
  identifier :name
@@ -687,6 +726,7 @@ end
687
726
  ```
688
727
 
689
728
  Output:
729
+
690
730
  ```json
691
731
  {
692
732
  "name": "John Doe",
@@ -695,6 +735,7 @@ Output:
695
735
  ```
696
736
 
697
737
  Usage (Proc Option):
738
+
698
739
  ```ruby
699
740
  class UserBlueprint < Blueprinter::Base
700
741
  identifier :name
@@ -703,6 +744,7 @@ end
703
744
  ```
704
745
 
705
746
  Output:
747
+
706
748
  ```json
707
749
  {
708
750
  "name": "John Doe",
@@ -712,14 +754,11 @@ Output:
712
754
 
713
755
  _NOTE:_ The field-level setting overrides the global config setting (for the field) if both are set.
714
756
 
715
- ---
716
757
  </details>
717
758
 
718
-
719
759
  <details>
720
760
  <summary>Transform Classes</summary>
721
761
 
722
- ---
723
762
 
724
763
  Blueprinter provides the ability to specify `transform`s on views, which enable further
725
764
  processing and transforming of resulting view field hashes prior to serialization.
@@ -731,6 +770,7 @@ Whatever is returned from this `transform` method will end up being the resultin
731
770
  #### Example
732
771
 
733
772
  Create a Transform class extending from `Blueprinter::Transformer`
773
+
734
774
  ```ruby
735
775
  class DynamicFieldTransformer < Blueprinter::Transformer
736
776
  def transform(hash, object, options)
@@ -752,6 +792,7 @@ end
752
792
  ```
753
793
 
754
794
  Then specify the transform to use for the view.
795
+
755
796
  ```ruby
756
797
  class UserBlueprint < Blueprinter::Base
757
798
  fields :first_name, :last_name
@@ -762,6 +803,7 @@ end
762
803
  #### Global Transforms
763
804
 
764
805
  You can also specify global default transformers. Create one or more transformer classes extending from `Blueprinter::Transformer` and set the `default_transformers` configuration
806
+
765
807
  ```ruby
766
808
  class LowerCamelTransformer < Blueprinter::Transformer
767
809
  def transform(hash, _object, _options)
@@ -778,19 +820,18 @@ end
778
820
 
779
821
  **Note: Any transforms specified on a per-blueprint or per-view level will override the `default_transformers` in the configuration.**
780
822
 
781
- ---
782
823
  </details>
783
824
 
784
825
  <details>
785
826
  <summary>Configurable Extractors</summary>
786
827
 
787
- ---
788
828
 
789
829
  Blueprinter gets a given objects' values from the fields definitions using extractor classes. You can substitute your own extractor class globally or per-field.
790
830
 
791
831
  #### Examples
792
832
 
793
833
  For a specific kind of field, create an extractor class extending from `Blueprinter::Extractor`
834
+
794
835
  ```ruby
795
836
  class MyFieldExtractor < Blueprinter::Extractor
796
837
  def extract(_field_name, _object, _local_options, _options={})
@@ -807,6 +848,7 @@ end
807
848
  ```
808
849
 
809
850
  For a global default, create an extractor class extending from `Blueprinter::AutoExtractor` and set the `extractor_default` configuration
851
+
810
852
  ```ruby
811
853
  class MyAutoExtractor < Blueprinter::AutoExtractor
812
854
  def initialize
@@ -830,13 +872,11 @@ Blueprinter.configure do |config|
830
872
  end
831
873
  ```
832
874
 
833
- ---
834
875
  </details>
835
876
 
836
877
  <details>
837
878
  <summary>Sorting Fields</summary>
838
879
 
839
- ---
840
880
 
841
881
  By default the response sorts the keys by name. If you want the fields to be sorted in the order of definition, use the below configuration option.
842
882
 
@@ -857,6 +897,7 @@ end
857
897
  ```
858
898
 
859
899
  Output:
900
+
860
901
  ```json
861
902
  {
862
903
  "name": "John Doe",
@@ -865,14 +906,11 @@ Output:
865
906
  }
866
907
  ```
867
908
 
868
- ---
869
909
  </details>
870
910
 
871
-
872
911
  <details>
873
912
  <summary>Deprecations</summary>
874
913
 
875
- ---
876
914
 
877
915
  When functionality in Blueprinter is invoked, that has been deprecated, the default behavior is to
878
916
  write a deprecation notice to stderror.
@@ -885,21 +923,19 @@ However, deprecations can be configured to report at three different levels:
885
923
  | `:raise` | Deprecations will be raised as `Blueprinter::BlueprinterError`s |
886
924
  | `:silence` | Deprecations will be silenced and will not be raised or logged |
887
925
 
888
- ### Example:
926
+ ### Example - deprecations
927
+
889
928
  ```ruby
890
929
  Blueprinter.configure do |config|
891
930
  config.deprecations = :raise
892
931
  end
893
932
  ```
894
933
 
895
- ---
896
934
  </details>
897
935
 
898
-
899
936
  <details>
900
937
  <summary>render_as_hash</summary>
901
938
 
902
- ---
903
939
 
904
940
  Same as `render`, returns a Ruby Hash.
905
941
 
@@ -918,14 +954,11 @@ Output:
918
954
  }
919
955
  ```
920
956
 
921
- ---
922
957
  </details>
923
958
 
924
-
925
959
  <details>
926
960
  <summary>render_as_json</summary>
927
961
 
928
- ---
929
962
 
930
963
  Same as `render`, returns a Ruby Hash JSONified. This will call JSONify all keys and values.
931
964
 
@@ -944,11 +977,10 @@ Output:
944
977
  }
945
978
  ```
946
979
 
947
- ---
948
980
  </details>
949
981
 
950
-
951
982
  ## Installation
983
+
952
984
  Add this line to your application's Gemfile:
953
985
 
954
986
  ```ruby
@@ -956,13 +988,15 @@ gem 'blueprinter'
956
988
  ```
957
989
 
958
990
  And then execute:
991
+
959
992
  ```bash
960
- $ bundle
993
+ bundle
961
994
  ```
962
995
 
963
996
  Or install it yourself as:
997
+
964
998
  ```bash
965
- $ gem install blueprinter
999
+ gem install blueprinter
966
1000
  ```
967
1001
 
968
1002
  You should also have `require 'json'` already in your project if you are not using Rails or if you are not using Oj.
@@ -1002,12 +1036,15 @@ end
1002
1036
  _NOTE:_ You should be doing this only if you aren't using `yajl-ruby` through the JSON API by requiring `yajl/json_gem`. More details [here](https://github.com/brianmario/yajl-ruby#json-gem-compatibility-api). In this case, `JSON.generate` is patched to use `Yajl::Encoder.encode` internally.
1003
1037
 
1004
1038
  ## Contributing
1005
- Feel free to browse the issues, converse, and make pull requests. If you need help, first please see if there is already an issue for your problem. Otherwise, go ahead and make a new issue.
1039
+
1040
+ Please read our [Contributing](CONTRIBUTING.md) file
1006
1041
 
1007
1042
  ### Tests
1043
+
1008
1044
  You can run tests with `bundle exec rake`.
1009
1045
 
1010
1046
  ### Maintain The Docs
1047
+
1011
1048
  We use Yard for documentation. Here are the following documentation rules:
1012
1049
 
1013
1050
  - Document all public methods we expect to be utilized by the end developers.
@@ -1022,7 +1059,9 @@ documentation rules:
1022
1059
  - Methods that are not set to private due to ruby visibility rule limitations should be marked with `@api private`.
1023
1060
 
1024
1061
  ### Releasing a New Version
1062
+
1025
1063
  To release a new version, change the version number in `version.rb`, and update the `CHANGELOG.md`. Finally, maintainers need to run `bundle exec rake release`, which will automatically create a git tag for the version, push git commits and tags to Github, and push the `.gem` file to rubygems.org.
1026
1064
 
1027
1065
  ## License
1066
+
1028
1067
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).