clowne 0.1.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +11 -45
  3. data/.travis.yml +14 -21
  4. data/CHANGELOG.md +30 -0
  5. data/Gemfile +11 -7
  6. data/README.md +38 -18
  7. data/Rakefile +3 -3
  8. data/clowne.gemspec +17 -10
  9. data/docs/.nojekyll +0 -0
  10. data/docs/.rubocop.yml +8 -2
  11. data/docs/CNAME +1 -0
  12. data/docs/README.md +131 -0
  13. data/docs/_sidebar.md +25 -0
  14. data/docs/active_record.md +4 -7
  15. data/docs/after_clone.md +53 -0
  16. data/docs/after_persist.md +77 -0
  17. data/docs/architecture.md +2 -5
  18. data/docs/assets/docsify.min.js +1 -0
  19. data/docs/assets/prism-ruby.min.js +1 -0
  20. data/docs/assets/styles.css +348 -0
  21. data/docs/assets/vue.css +1 -0
  22. data/docs/clone_mapper.md +59 -0
  23. data/docs/customization.md +6 -7
  24. data/docs/exclude_association.md +6 -8
  25. data/docs/finalize.md +11 -15
  26. data/docs/from_v02_to_v1.md +83 -0
  27. data/docs/getting_started.md +171 -0
  28. data/docs/implicit_cloner.md +2 -5
  29. data/docs/include_association.md +24 -10
  30. data/docs/index.html +29 -0
  31. data/docs/init_as.md +13 -9
  32. data/docs/inline_configuration.md +5 -6
  33. data/docs/nullify.md +3 -7
  34. data/docs/operation.md +55 -0
  35. data/docs/parameters.md +112 -0
  36. data/docs/sequel.md +16 -22
  37. data/docs/supported_adapters.md +3 -6
  38. data/docs/testing.md +194 -0
  39. data/docs/traits.md +1 -4
  40. data/gemfiles/activerecord42.gemfile +7 -5
  41. data/gemfiles/jruby.gemfile +8 -6
  42. data/gemfiles/railsmaster.gemfile +8 -6
  43. data/lib/clowne.rb +12 -9
  44. data/lib/clowne/adapters/active_record.rb +4 -5
  45. data/lib/clowne/adapters/active_record/associations.rb +8 -6
  46. data/lib/clowne/adapters/active_record/associations/base.rb +1 -5
  47. data/lib/clowne/adapters/active_record/associations/belongs_to.rb +29 -0
  48. data/lib/clowne/adapters/active_record/associations/has_one.rb +3 -2
  49. data/lib/clowne/adapters/active_record/dsl.rb +2 -2
  50. data/lib/clowne/adapters/active_record/resolvers/association.rb +38 -0
  51. data/lib/clowne/adapters/base.rb +49 -44
  52. data/lib/clowne/adapters/base/association.rb +24 -15
  53. data/lib/clowne/adapters/registry.rb +49 -0
  54. data/lib/clowne/adapters/sequel.rb +14 -10
  55. data/lib/clowne/adapters/sequel/associations.rb +6 -6
  56. data/lib/clowne/adapters/sequel/associations/base.rb +9 -5
  57. data/lib/clowne/adapters/sequel/associations/many_to_many.rb +6 -2
  58. data/lib/clowne/adapters/sequel/associations/one_to_many.rb +7 -2
  59. data/lib/clowne/adapters/sequel/associations/one_to_one.rb +7 -2
  60. data/lib/clowne/adapters/sequel/operation.rb +35 -0
  61. data/lib/clowne/adapters/sequel/record_wrapper.rb +0 -16
  62. data/lib/clowne/adapters/sequel/resolvers/after_persist.rb +22 -0
  63. data/lib/clowne/adapters/sequel/resolvers/association.rb +51 -0
  64. data/lib/clowne/adapters/sequel/specifications/after_persist_does_not_support.rb +15 -0
  65. data/lib/clowne/cloner.rb +49 -21
  66. data/lib/clowne/declarations.rb +15 -12
  67. data/lib/clowne/declarations/after_clone.rb +21 -0
  68. data/lib/clowne/declarations/after_persist.rb +21 -0
  69. data/lib/clowne/declarations/base.rb +13 -0
  70. data/lib/clowne/declarations/exclude_association.rb +2 -2
  71. data/lib/clowne/declarations/finalize.rb +5 -4
  72. data/lib/clowne/declarations/include_association.rb +16 -2
  73. data/lib/clowne/declarations/init_as.rb +5 -4
  74. data/lib/clowne/declarations/nullify.rb +4 -3
  75. data/lib/clowne/declarations/trait.rb +1 -0
  76. data/lib/clowne/dsl.rb +9 -0
  77. data/lib/clowne/ext/lambda_as_proc.rb +17 -0
  78. data/lib/clowne/ext/orm_ext.rb +1 -1
  79. data/lib/clowne/ext/record_key.rb +12 -0
  80. data/lib/clowne/ext/string_constantize.rb +9 -3
  81. data/lib/clowne/ext/yield_self_then.rb +25 -0
  82. data/lib/clowne/planner.rb +16 -3
  83. data/lib/clowne/resolvers/after_clone.rb +17 -0
  84. data/lib/clowne/resolvers/after_persist.rb +18 -0
  85. data/lib/clowne/resolvers/finalize.rb +12 -0
  86. data/lib/clowne/resolvers/init_as.rb +13 -0
  87. data/lib/clowne/resolvers/nullify.rb +15 -0
  88. data/lib/clowne/rspec.rb +5 -0
  89. data/lib/clowne/rspec/clone_association.rb +99 -0
  90. data/lib/clowne/rspec/clone_associations.rb +26 -0
  91. data/lib/clowne/rspec/helpers.rb +35 -0
  92. data/lib/clowne/utils/clone_mapper.rb +26 -0
  93. data/lib/clowne/utils/operation.rb +95 -0
  94. data/lib/clowne/utils/options.rb +39 -0
  95. data/lib/clowne/utils/params.rb +64 -0
  96. data/lib/clowne/utils/plan.rb +90 -0
  97. data/lib/clowne/version.rb +1 -1
  98. metadata +99 -45
  99. data/docs/alternatives.md +0 -26
  100. data/docs/basic_example.md +0 -66
  101. data/docs/configuration.md +0 -29
  102. data/docs/execution_order.md +0 -14
  103. data/docs/installation.md +0 -16
  104. data/docs/web/.gitignore +0 -11
  105. data/docs/web/core/Footer.js +0 -92
  106. data/docs/web/i18n/en.json +0 -134
  107. data/docs/web/package.json +0 -14
  108. data/docs/web/pages/en/help.js +0 -50
  109. data/docs/web/pages/en/index.js +0 -231
  110. data/docs/web/pages/en/users.js +0 -47
  111. data/docs/web/sidebars.json +0 -30
  112. data/docs/web/siteConfig.js +0 -44
  113. data/docs/web/static/css/custom.css +0 -229
  114. data/docs/web/static/fonts/FiraCode-Medium.woff +0 -0
  115. data/docs/web/static/fonts/FiraCode-Regular.woff +0 -0
  116. data/docs/web/static/fonts/StemText.woff +0 -0
  117. data/docs/web/static/fonts/StemTextBold.woff +0 -0
  118. data/docs/web/static/img/favicon/favicon.ico +0 -0
  119. data/docs/web/yarn.lock +0 -1741
  120. data/lib/clowne/adapters/active_record/association.rb +0 -34
  121. data/lib/clowne/adapters/base/finalize.rb +0 -19
  122. data/lib/clowne/adapters/base/init_as.rb +0 -21
  123. data/lib/clowne/adapters/base/nullify.rb +0 -19
  124. data/lib/clowne/adapters/sequel/association.rb +0 -47
  125. data/lib/clowne/plan.rb +0 -81
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Clowne
4
- VERSION = '0.1.0'
4
+ VERSION = "1.3.0"
5
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clowne
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  - Sverchkov Nikolay
9
9
  autorequire:
10
- bindir: exe
10
+ bindir: bin
11
11
  cert_chain: []
12
- date: 2018-02-01 00:00:00.000000000 Z
12
+ date: 2021-05-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -17,28 +17,34 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '1.14'
20
+ version: '2.0'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '1.14'
27
+ version: '2.0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '10.0'
34
+ version: '12.3'
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 12.3.3
35
38
  type: :development
36
39
  prerelease: false
37
40
  version_requirements: !ruby/object:Gem::Requirement
38
41
  requirements:
39
42
  - - "~>"
40
43
  - !ruby/object:Gem::Version
41
- version: '10.0'
44
+ version: '12.3'
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 12.3.3
42
48
  - !ruby/object:Gem::Dependency
43
49
  name: rspec
44
50
  requirement: !ruby/object:Gem::Requirement
@@ -59,42 +65,70 @@ dependencies:
59
65
  requirements:
60
66
  - - "~>"
61
67
  - !ruby/object:Gem::Version
62
- version: '4.8'
68
+ version: '5'
63
69
  type: :development
64
70
  prerelease: false
65
71
  version_requirements: !ruby/object:Gem::Requirement
66
72
  requirements:
67
73
  - - "~>"
68
74
  - !ruby/object:Gem::Version
69
- version: '4.8'
75
+ version: '5'
70
76
  - !ruby/object:Gem::Dependency
71
77
  name: rubocop
72
78
  requirement: !ruby/object:Gem::Requirement
73
79
  requirements:
74
80
  - - "~>"
75
81
  - !ruby/object:Gem::Version
76
- version: '0.51'
82
+ version: 0.75.0
77
83
  type: :development
78
84
  prerelease: false
79
85
  version_requirements: !ruby/object:Gem::Requirement
80
86
  requirements:
81
87
  - - "~>"
82
88
  - !ruby/object:Gem::Version
83
- version: '0.51'
89
+ version: 0.75.0
84
90
  - !ruby/object:Gem::Dependency
85
91
  name: rubocop-md
86
92
  requirement: !ruby/object:Gem::Requirement
87
93
  requirements:
88
94
  - - "~>"
89
95
  - !ruby/object:Gem::Version
90
- version: '0.2'
96
+ version: 0.3.0
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.3.0
104
+ - !ruby/object:Gem::Dependency
105
+ name: rubocop-rspec
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.36.0
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.36.0
118
+ - !ruby/object:Gem::Dependency
119
+ name: standard
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.1.5
91
125
  type: :development
92
126
  prerelease: false
93
127
  version_requirements: !ruby/object:Gem::Requirement
94
128
  requirements:
95
129
  - - "~>"
96
130
  - !ruby/object:Gem::Version
97
- version: '0.2'
131
+ version: 0.1.5
98
132
  description: A flexible gem for cloning your models.
99
133
  email:
100
134
  - palkan@evilmartians.com
@@ -118,62 +152,55 @@ files:
118
152
  - bin/console
119
153
  - bin/setup
120
154
  - clowne.gemspec
155
+ - docs/.nojekyll
121
156
  - docs/.rubocop.yml
157
+ - docs/CNAME
158
+ - docs/README.md
159
+ - docs/_sidebar.md
122
160
  - docs/active_record.md
123
- - docs/alternatives.md
161
+ - docs/after_clone.md
162
+ - docs/after_persist.md
124
163
  - docs/architecture.md
125
- - docs/basic_example.md
126
- - docs/configuration.md
164
+ - docs/assets/docsify.min.js
165
+ - docs/assets/prism-ruby.min.js
166
+ - docs/assets/styles.css
167
+ - docs/assets/vue.css
168
+ - docs/clone_mapper.md
127
169
  - docs/customization.md
128
170
  - docs/exclude_association.md
129
- - docs/execution_order.md
130
171
  - docs/finalize.md
172
+ - docs/from_v02_to_v1.md
173
+ - docs/getting_started.md
131
174
  - docs/implicit_cloner.md
132
175
  - docs/include_association.md
176
+ - docs/index.html
133
177
  - docs/init_as.md
134
178
  - docs/inline_configuration.md
135
- - docs/installation.md
136
179
  - docs/nullify.md
180
+ - docs/operation.md
181
+ - docs/parameters.md
137
182
  - docs/sequel.md
138
183
  - docs/supported_adapters.md
184
+ - docs/testing.md
139
185
  - docs/traits.md
140
- - docs/web/.gitignore
141
- - docs/web/core/Footer.js
142
- - docs/web/i18n/en.json
143
- - docs/web/package.json
144
- - docs/web/pages/en/help.js
145
- - docs/web/pages/en/index.js
146
- - docs/web/pages/en/users.js
147
- - docs/web/sidebars.json
148
- - docs/web/siteConfig.js
149
- - docs/web/static/css/custom.css
150
- - docs/web/static/fonts/FiraCode-Medium.woff
151
- - docs/web/static/fonts/FiraCode-Regular.woff
152
- - docs/web/static/fonts/StemText.woff
153
- - docs/web/static/fonts/StemTextBold.woff
154
- - docs/web/static/img/favicon/favicon.ico
155
- - docs/web/yarn.lock
156
186
  - gemfiles/activerecord42.gemfile
157
187
  - gemfiles/jruby.gemfile
158
188
  - gemfiles/railsmaster.gemfile
159
189
  - lib/clowne.rb
160
190
  - lib/clowne/adapters/active_record.rb
161
- - lib/clowne/adapters/active_record/association.rb
162
191
  - lib/clowne/adapters/active_record/associations.rb
163
192
  - lib/clowne/adapters/active_record/associations/base.rb
193
+ - lib/clowne/adapters/active_record/associations/belongs_to.rb
164
194
  - lib/clowne/adapters/active_record/associations/has_and_belongs_to_many.rb
165
195
  - lib/clowne/adapters/active_record/associations/has_many.rb
166
196
  - lib/clowne/adapters/active_record/associations/has_one.rb
167
197
  - lib/clowne/adapters/active_record/associations/noop.rb
168
198
  - lib/clowne/adapters/active_record/dsl.rb
199
+ - lib/clowne/adapters/active_record/resolvers/association.rb
169
200
  - lib/clowne/adapters/base.rb
170
201
  - lib/clowne/adapters/base/association.rb
171
- - lib/clowne/adapters/base/finalize.rb
172
- - lib/clowne/adapters/base/init_as.rb
173
- - lib/clowne/adapters/base/nullify.rb
174
202
  - lib/clowne/adapters/registry.rb
175
203
  - lib/clowne/adapters/sequel.rb
176
- - lib/clowne/adapters/sequel/association.rb
177
204
  - lib/clowne/adapters/sequel/associations.rb
178
205
  - lib/clowne/adapters/sequel/associations/base.rb
179
206
  - lib/clowne/adapters/sequel/associations/many_to_many.rb
@@ -181,9 +208,16 @@ files:
181
208
  - lib/clowne/adapters/sequel/associations/one_to_many.rb
182
209
  - lib/clowne/adapters/sequel/associations/one_to_one.rb
183
210
  - lib/clowne/adapters/sequel/copier.rb
211
+ - lib/clowne/adapters/sequel/operation.rb
184
212
  - lib/clowne/adapters/sequel/record_wrapper.rb
213
+ - lib/clowne/adapters/sequel/resolvers/after_persist.rb
214
+ - lib/clowne/adapters/sequel/resolvers/association.rb
215
+ - lib/clowne/adapters/sequel/specifications/after_persist_does_not_support.rb
185
216
  - lib/clowne/cloner.rb
186
217
  - lib/clowne/declarations.rb
218
+ - lib/clowne/declarations/after_clone.rb
219
+ - lib/clowne/declarations/after_persist.rb
220
+ - lib/clowne/declarations/base.rb
187
221
  - lib/clowne/declarations/exclude_association.rb
188
222
  - lib/clowne/declarations/finalize.rb
189
223
  - lib/clowne/declarations/include_association.rb
@@ -191,15 +225,36 @@ files:
191
225
  - lib/clowne/declarations/nullify.rb
192
226
  - lib/clowne/declarations/trait.rb
193
227
  - lib/clowne/dsl.rb
228
+ - lib/clowne/ext/lambda_as_proc.rb
194
229
  - lib/clowne/ext/orm_ext.rb
230
+ - lib/clowne/ext/record_key.rb
195
231
  - lib/clowne/ext/string_constantize.rb
196
- - lib/clowne/plan.rb
232
+ - lib/clowne/ext/yield_self_then.rb
197
233
  - lib/clowne/planner.rb
234
+ - lib/clowne/resolvers/after_clone.rb
235
+ - lib/clowne/resolvers/after_persist.rb
236
+ - lib/clowne/resolvers/finalize.rb
237
+ - lib/clowne/resolvers/init_as.rb
238
+ - lib/clowne/resolvers/nullify.rb
239
+ - lib/clowne/rspec.rb
240
+ - lib/clowne/rspec/clone_association.rb
241
+ - lib/clowne/rspec/clone_associations.rb
242
+ - lib/clowne/rspec/helpers.rb
243
+ - lib/clowne/utils/clone_mapper.rb
244
+ - lib/clowne/utils/operation.rb
245
+ - lib/clowne/utils/options.rb
246
+ - lib/clowne/utils/params.rb
247
+ - lib/clowne/utils/plan.rb
198
248
  - lib/clowne/version.rb
199
- homepage: https://github.com/palkan/clowne
249
+ homepage: https://github.com/clowne-rb/clowne
200
250
  licenses:
201
251
  - MIT
202
- metadata: {}
252
+ metadata:
253
+ bug_tracker_uri: http://github.com/clowne-rb/clowne/issues
254
+ changelog_uri: https://github.com/clowne-rb/clowne/blob/master/CHANGELOG.md
255
+ documentation_uri: https://clowne.evilmartians.io/
256
+ homepage_uri: https://clowne.evilmartians.io/
257
+ source_code_uri: http://github.com/clowne-rb/clowne
203
258
  post_install_message:
204
259
  rdoc_options: []
205
260
  require_paths:
@@ -215,9 +270,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
270
  - !ruby/object:Gem::Version
216
271
  version: '0'
217
272
  requirements: []
218
- rubyforge_project:
219
- rubygems_version: 2.6.13
273
+ rubygems_version: 3.0.3
220
274
  signing_key:
221
275
  specification_version: 4
222
- summary: A flexible gem for cloning your models.
276
+ summary: A flexible gem for cloning your models
223
277
  test_files: []
data/docs/alternatives.md DELETED
@@ -1,26 +0,0 @@
1
- ---
2
- id: alternatives
3
- title: Motivation & Alternatives
4
- ---
5
-
6
- ### Why did we decide to build our own cloning gem instead of using the existing solutions?
7
-
8
- First, the existing solutions turned out not to be stable and flexible enough for us.
9
-
10
- Secondly, they are Rails-only (or, more precisely, ActiveRecord-only).
11
-
12
- Nevertheless, thanks to [amoeba](https://github.com/amoeba-rb/amoeba) and [deep_cloneable](https://github.com/moiristo/deep_cloneable) for inspiration.
13
-
14
- For ActiveRecord we support amoeba-like [in-model configuration](active_record.md) and you can add missing DSL declarations yourself [easily](customization.md).
15
-
16
- We also provide an ability to specify cloning [configuration in-place](inline_configuration.md) like `deep_clonable` does.
17
-
18
- So, we took the best of these too and brought to the outside-of-Rails world.
19
-
20
- ### Why build a gem to clone models at all?
21
-
22
- That's a good question. Of course, you can write plain old Ruby services do handle the cloning logic. But for complex models hierarchies, this approach has major disadvantages: high code complexity and lack of re-usability.
23
-
24
- The things become even worse when you deal with STI models and different cloning contexts.
25
-
26
- That's why we decided to build a specific cloning tool.
@@ -1,66 +0,0 @@
1
- ---
2
- id: basic_example
3
- title: Basic Example
4
- ---
5
-
6
- Assume that you have the following model:
7
-
8
- ```ruby
9
- class User < ActiveRecord::Base
10
- # create_table :users do |t|
11
- # t.string :login
12
- # t.string :email
13
- # t.timestamps null: false
14
- # end
15
-
16
- has_one :profile
17
- has_many :posts
18
- end
19
- ```
20
-
21
- Let's declare our cloners first:
22
-
23
- ```ruby
24
- class UserCloner < Clowne::Cloner
25
- adapter :active_record
26
-
27
- include_association :profile, clone_with: SpecialProfileCloner
28
- include_association :posts
29
-
30
- nullify :login
31
-
32
- # params here is an arbitrary Hash passed into cloner
33
- finalize do |_source, record, params|
34
- record.email = params[:email]
35
- end
36
- end
37
-
38
- class SpecialProfileCloner < Clowne::Cloner
39
- adapter :active_record
40
-
41
- nullify :name
42
- end
43
- ```
44
-
45
- Now you can use `UserCloner` to clone existing records:
46
-
47
- ```ruby
48
- user = User.last
49
- #=> <#User(login: 'clown', email: 'clown@circus.example.com')>
50
-
51
- cloned = UserCloner.call(user, email: 'fake@example.com')
52
- cloned.persisted?
53
- # => false
54
-
55
- cloned.save!
56
- cloned.login
57
- # => nil
58
- cloned.email
59
- # => "fake@example.com"
60
-
61
- # associations:
62
- cloned.posts.count == user.posts.count
63
- # => true
64
- cloned.profile.name
65
- # => nil
66
- ```
@@ -1,29 +0,0 @@
1
- ---
2
- id: configuration
3
- title: Configuration
4
- ---
5
-
6
- Basic cloner implementation looks like
7
-
8
- ```ruby
9
- class SomeCloner < Clowne::Cloner
10
- adapter :active_record # or adapter Clowne::ActiveRecord::Adapter
11
- # some implementation ...
12
- end
13
- ```
14
-
15
- But you can configure the default adapter for cloners:
16
-
17
- ```ruby
18
- # somewhere in initializers
19
- Clowne.default_adapter = :active_record
20
- ```
21
-
22
- and skip adapter declaration
23
-
24
- ```ruby
25
- class SomeCloner < Clowne::Cloner
26
- # some implementation ...
27
- end
28
- ```
29
- See the list of [available adapters](supported_adapters.md).
@@ -1,14 +0,0 @@
1
- ---
2
- id: execution_order
3
- title: Execution Order
4
- ---
5
-
6
- The order of cloning actions depends on the adapter (i.e., could be customized).
7
-
8
- All built-in adapters have the same order:
9
- - init clone (see [`init_as`](init_as.md))
10
- - clone associations
11
- - nullify attributes
12
- - run [`finalize`](finalize.md) blocks
13
-
14
- The order of [`finalize`](finalize.md) blocks is the order they've been written.
data/docs/installation.md DELETED
@@ -1,16 +0,0 @@
1
- ---
2
- id: installation
3
- title: Installation
4
- ---
5
-
6
- To install Clowne with RubyGems:
7
-
8
- ```ruby
9
- gem install clowne
10
- ```
11
-
12
- Or add this line to your application's Gemfile:
13
-
14
- ```ruby
15
- gem 'clowne'
16
- ```