clerq 0.2.0 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/CHANGELOG.md +35 -2
  4. data/Gemfile.lock +24 -0
  5. data/README.md +123 -39
  6. data/Rakefile +1 -0
  7. data/clerq.gemspec +4 -4
  8. data/clerq.thor +28 -0
  9. data/docs/README.md +415 -0
  10. data/docs/promo.png +0 -0
  11. data/lib/assets/knb/SRS-RUP.md +1 -0
  12. data/lib/assets/knb/business-case.md +135 -0
  13. data/lib/assets/knb/requirement-classification.md +27 -0
  14. data/lib/assets/knb/requirement-life-cycle.md +47 -0
  15. data/lib/assets/knb/requirement-quality.md +13 -0
  16. data/lib/assets/knb/vision-document.md +191 -0
  17. data/lib/assets/lib/clerq_doc.thor +119 -0
  18. data/lib/assets/lib/colonize_repo.rb +82 -0
  19. data/lib/assets/lib/markup_macro.rb +77 -0
  20. data/lib/assets/lib/markup_node.rb +86 -0
  21. data/lib/assets/lib/spec/colonize_repo_spec.rb +85 -0
  22. data/lib/assets/lib/spec/markup_macro_spec.rb +91 -0
  23. data/lib/assets/lib/spec/markup_node_spec.rb +34 -0
  24. data/lib/assets/new/clerq.thor.tt +30 -1
  25. data/lib/assets/new/content.md.tt +1 -0
  26. data/lib/assets/promo/bin/Clerq SRS.docx +0 -0
  27. data/lib/assets/promo/bin/Clerq SRS.md +62 -252
  28. data/lib/assets/promo/bin/assets/promo_dark.png +0 -0
  29. data/lib/assets/promo/promo.thor +1 -1
  30. data/lib/assets/promo/src/clerq.md +10 -12
  31. data/lib/assets/tt/default.md.erb +3 -34
  32. data/lib/clerq.rb +7 -2
  33. data/lib/clerq/cli.rb +37 -47
  34. data/lib/clerq/entities/node.rb +11 -5
  35. data/lib/clerq/properties.rb +1 -3
  36. data/lib/clerq/repositories.rb +0 -1
  37. data/lib/clerq/repositories/file_repository.rb +1 -0
  38. data/lib/clerq/repositories/node_repository.rb +7 -6
  39. data/lib/clerq/services.rb +8 -0
  40. data/lib/clerq/services/check_assembly.rb +108 -0
  41. data/lib/clerq/{interactors → services}/create_node.rb +4 -5
  42. data/lib/clerq/services/load_assembly.rb +54 -0
  43. data/lib/clerq/{interactors/query_assembly.rb → services/query_node.rb} +15 -12
  44. data/lib/clerq/{interactors → services}/query_template.rb +3 -8
  45. data/lib/clerq/services/read_node.rb +101 -0
  46. data/lib/clerq/services/render_erb.rb +29 -0
  47. data/lib/clerq/{interactors/render_assembly.rb → services/render_node.rb} +8 -12
  48. data/lib/clerq/services/service.rb +25 -0
  49. data/lib/clerq/version.rb +1 -1
  50. data/promo.png +0 -0
  51. metadata +41 -25
  52. data/TODO.md +0 -7
  53. data/lib/assets/tt/pandoc.md.erb +0 -89
  54. data/lib/clerq/interactors.rb +0 -5
  55. data/lib/clerq/interactors/check_assembly.rb +0 -77
  56. data/lib/clerq/interactors/interactor.rb +0 -26
  57. data/lib/clerq/render_erb.rb +0 -33
  58. data/lib/clerq/repositories/node_reader.rb +0 -107
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4d9114f078750db97781623afefdbd33f39809dc02c6f68dfe8303d0764b751
4
- data.tar.gz: d9cb6491239baa42fdc945ad0282aa3683aa850079de52c26bd5f37a370e01fa
3
+ metadata.gz: 74e2ec342a403fb52eef258b5c8e537c9b64ec266f31f934edaaefe8cffadfd1
4
+ data.tar.gz: 1f2baaec876667bfd67d99e75d36abc20e4f1ddcbe99e60687093d48325b51f9
5
5
  SHA512:
6
- metadata.gz: cf035ee76e81ff8f565e5d5448773185075839589ebea7773ed8ace9e7477bb8700c805419e17dbc358608b57db01008fc056f7fee203b37bf1966d6ed4c9ff7
7
- data.tar.gz: 1758cc13f790117e93944ccc17f97bb738a26cede5c3e70d462dedae9c8deb4aedeaffe868f3056d527ab207864cef083ffdb48b6eabf63c34be3f623639bbb8
6
+ metadata.gz: 0dafc680ff7353b9102d2f8d869258c19980d2b35202c2c2fc10de639cd3223d619af8726e592a65924f5c30bcee0fc0ded2ab6923df193ac1dd5fdbed597b1b
7
+ data.tar.gz: b6f732d36363c8a5eb4d283b14fa27c209909724820676b19541d767cee77cae69113dad1fea454e7aaf474c4ac06982543a9ffe34fbc337ad8a24c57dd38ca2
data/.gitignore CHANGED
@@ -7,4 +7,7 @@
7
7
  /doc/
8
8
  /pkg/
9
9
  /spec/reports/
10
- Gemfile.lock
10
+ /docs/.*
11
+ /docs/_*
12
+ /docs/Gemfile*
13
+ TODO.md
data/CHANGELOG.md CHANGED
@@ -1,8 +1,41 @@
1
1
  # Change log
2
2
 
3
- ## 0.2.0 (2019-11-23)
3
+ ## 0.3.4 (2021-06-01)
4
+
5
+ * Now the gem works for both Ruby versions 2.X and 3.X.
6
+ * Improved templates. MarkupNode was extracted to separate file and single template defalult.md.erb was left; cleaned templates tests.
7
+ * Improved `promo:publish` command and now it's using default.md.erb
8
+
9
+ ## 0.3.3 (2021-05-25)
10
+
11
+ * Updated keyword argument in Service class to support Ruby 3. If you need Ruby 2.X support, you should use v0.3.2.
12
+ * Updated `minitest`, `bundler` and `thor` dependencies.
13
+ * Improved `default.md.erb` and `pandoc.md.erb` - now it adds automatic title `.id` when original title is empty.
14
+
15
+ ## 0.3.2 (2020-07-05)
16
+
17
+ * Updated `rake`, `bundler`, and `thor` dependencies.
18
+
19
+ ## 0.3.1 (2019-12-13)
4
20
 
5
- Changes:
21
+ * Fixed error with reading files that read attributes to body.
22
+ * Added `mm` command to `<project>.thor` that creates "Meeting Minutes" files in `<project>/mm` folder.
23
+
24
+ ## 0.3.0 (2019-12-04)
25
+
26
+ * Meet services instead of interactors. All interactors removed and their responsibility moved to appropriate services.
27
+ * Refactored printing information about repository loading progress. Now `ReadNode.call(on_error: )` accepts `on_error` callback and you can provide any method proc or lambda there like `lambda {|err| puts err}`.
28
+ * Refactored previous behavior where interactors loaded repository by QueryAssembly interactor. Now it is responsibility of `LoadAssembly` service and other services that require repository just get it through parameter.
29
+ * `clerq new PROJECT` command brings the `lib\clerq_doc.thor` example of publishing and importing existing documents in the current clerq project repository. To see these just copy the file to root project folder near `<project>.thor` file.
30
+
31
+ ## 0.2.1 (2019-11-29)
32
+
33
+ * Enhanced the `Node` class that brings the possibility to provide node id through `{{id: <id>}}` metadata attribute. But it will just skipped when id is already provided by `# [<id>]`.
34
+ * Enhanced `NodeReader` class; now it supports three metadata attributes delimiters - `\n`, `;`, and `,` that can be mixed.
35
+ * `CheckAssembly` interactor replaced by `CheckAssembly` service that provides improved error information with nodes ids and source files names.
36
+ * `file_name` attribute changed to `filename` in `NodeReader`.
37
+
38
+ ## 0.2.0 (2019-11-23)
6
39
 
7
40
  * Started new project [Clerq Video Guide](https://github.com/nvoynov/clerq-video-guide) that provides example of using Clerq.
8
41
  * Done massive refactoring of source code; no more gateways.
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ clerq (0.3.4)
5
+ thor (~> 1.0.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ minitest (5.14.4)
11
+ rake (13.0.1)
12
+ thor (1.0.1)
13
+
14
+ PLATFORMS
15
+ x64-mingw32
16
+
17
+ DEPENDENCIES
18
+ bundler (~> 2.2.3)
19
+ clerq!
20
+ minitest (~> 5.14.2)
21
+ rake (~> 13.0)
22
+
23
+ BUNDLED WITH
24
+ 2.2.15
data/README.md CHANGED
@@ -18,6 +18,20 @@ Install it yourself as:
18
18
 
19
19
  $ gem install clerq
20
20
 
21
+ ## Promo
22
+
23
+ ![Clerq Promo Project](promo.png)
24
+
25
+ Inside Clerq there is a demo project that was created and is still used to develop Clerq itself and its script-extensions. You can see the project [here](https://github.com/nvoynov/clerq/tree/master/lib/assets/promo) ([requirements sources](https://github.com/nvoynov/clerq/tree/master/lib/assets/promo/src) and produced documents [Clerq SRS.md](https://github.com/nvoynov/clerq/blob/master/lib/assets/promo/bin/Clerq%20SRS.md), [Clerq SRS.docx](https://github.com/nvoynov/clerq/blob/master/lib/assets/promo/bin/Clerq%20SRS.docx))
26
+
27
+ I am sure this project will be useful when you get to know the product. So, I propose to open it now and look inside as you move forward. Do the following in your console:
28
+
29
+ $ clerq new promo
30
+ $ cd promo
31
+ $ clerq promo
32
+ $ atom .
33
+ $ thor list
34
+
21
35
  ## Usage
22
36
 
23
37
  The Clerq is entirely based on one single domain entity `Node` that represents a node of tree hierarchy and provides `id`, `title`, `body`, and `metadata` attributes. It supposes the following simple workflow:
@@ -47,7 +61,7 @@ The Clerq reads nodes from a set of separate files and assembles it to a single
47
61
 
48
62
  The first convention is the scheme how a markdown content becomes the `Node` entity.
49
63
 
50
- ```
64
+ ```markdown
51
65
  # [p2] Part two
52
66
  {{parent: top}}
53
67
 
@@ -59,9 +73,16 @@ Where
59
73
  * `#` familiar markdown header that indicates a new `node`;
60
74
  * `[p1]` is an optional identifier that becomes `node.id`;
61
75
  * `Part two` is an optional `node.title`;
62
- * `{{parent: top}}` in an optional metadata section that becomes `node.meta`;
76
+ * `{{parent: top}}` is an optional metadata section that becomes `node.meta`;
63
77
  * and finally `Body` is an optional `node.body`.
64
78
 
79
+ ```markdown
80
+ # Part two
81
+ {{id: p1, parent: top}}
82
+
83
+ Body
84
+ ```
85
+
65
86
  Every new header (`#`) at any level indicates a new node. When a file contains headers of different levels, the nodes will be created in a natural hierarchy based on header levels. So as the result of reading the content below, the Clerq will create the natural hierarchy with root node `Top` that holds two child nodes `First` and `Second`.
66
87
 
67
88
  ```markdown
@@ -74,29 +95,45 @@ One more extra thing is links. You can place links to other nodes in the body se
74
95
 
75
96
  #### IDs
76
97
 
77
- Each node must have its own unique id so that you can refer to it in other parts of the project. That's why the recommended practice is to put the id straight into the header `# [node id] node title`.
98
+ To be able to build a hierarchy or to refer to other nodes, one needs each node to have its unique id. And you can pass it straight into markdown header `# [node id] node title` or provide it through `{{id: }}`.
78
99
 
79
- ID can start with one dot, like `[.suffix]`, and clerq will add id of parent node. For the followed example, `[.fm]` will be translated to `[cm.fm]`.
100
+ ID can start with one dot, like `[.suffix]`, and clerq will build the node id as `node.parent_id + node.id`.
80
101
 
81
- ```
82
- # 3 Function requirements
102
+ When and ID is not provided, the Clerq will generate it automatically. Let's see the example of node:
103
+
104
+ ```markdown
105
+ # User requirements
106
+ ## Requirement 1
107
+ ## Requirement 2
108
+ # Function requirements
83
109
  ## [cm] Components
84
110
  ### [.fm] File manager
85
111
  ### Logger
86
112
  ```
87
113
 
88
- When an id is not provided, Clerq will generate it automatically, and you can freely combine nodes that have id and that has not. For the example above, the `Logger` will be identified as `[cm.01] Logger`.
114
+ According to rules mentioned above the example will be translated as followed:
115
+
116
+ ```markdown
117
+ # [01] User requirements
118
+ ## [01.01] Requirement 1
119
+ ## [01.02] Requirement 2
120
+ # [02] Function requirements
121
+ ## [cm] Components
122
+ ### [cm.fm] File manager
123
+ ### [cm.01] Logger
124
+ ```
89
125
 
90
126
  #### Meta
91
127
 
92
- The excerpt, the text in brackets `{{ }}` that follows by the header, contains node attributes. And the second convention mentioned in [Writing](#writing) section is two magic metadata attributes that specify parameters of a hierarchy:
128
+ The excerpt, the text in brackets `{{ }}` that follows by the header, contains node attributes. And the second convention mentioned in [Writing](#writing) section is the followed magic metadata attributes that specify parameters of a hierarchy:
93
129
 
94
- 1. `parent: <id>` indicates that the node belongs to a node with specified `id`;
95
- 2. `order_index: <id1> <id2>` indicates that child nodes must be lined up in specified order.
130
+ 1. `id: <id>` specifies id through metadata; when in provided together with `# [<id>]`, the last has priority;
131
+ 2. `parent: <id>` indicates that the node belongs to a node with specified `id`;
132
+ 3. `order_index: <id1> <id2>` indicates that child nodes must be lined up in specified order.
96
133
 
97
134
  You can place in metadata any simple string that suitable for providing additional information like status, originator, author, priority, etc. E.g.
98
135
 
99
- ```
136
+ ```markdown
100
137
  # [r.1]
101
138
  {{parent: r, status: draft}}
102
139
 
@@ -111,7 +148,7 @@ parent: r}}
111
148
 
112
149
  #### Assets
113
150
 
114
- When you want to provide some assets or links to something outside the repository you can provide the lint to the assets. Put the asset in the `bin/assets` folder and specify the link.
151
+ When you want to provide some assets or links to something outside the repository you can provide the link to the assets. Put the asset in the `bin/assets` folder and specify the link.
115
152
 
116
153
  ```markdown
117
154
  # [ent] Entities
@@ -197,40 +234,42 @@ A usual scenario will consist of two simple steps:
197
234
  1. Get data hierarchy from the repository.
198
235
  2. Do some processing of the hierarchy.
199
236
 
200
- Instead of adding extra scripts files somewhere in the project, you can write tasks to `<project>.thor` file and access to them through `thor <project>:<your-task> [<params>]`.
201
-
202
237
  #### Node class
203
238
 
204
239
  The [Writing](#writing) section provides the basic knowledge to understand Clerq, and now it is the right time to see the [Node class](https://github.com/nvoynov/clerq/blob/master/lib/clerq/entities/node.rb). It implements the Composite pattern.
205
240
 
206
- #### Interactors
241
+ #### Services
207
242
 
208
- Clerq provides five followed interactors:
243
+ Clerq provides the following main service objects:
209
244
 
210
- * `QueryAssembly` provides assembly of repository as root Node;
245
+ * `LoadAssembly` loads whole repository to Node class;
211
246
  * `CheckAssembly` checks the assembly for errors (ids and links);
212
- * `RenderAssembly` render assembly by provided erb-template;
247
+ * `QueryNode` provides ability to query nodes from assembly;
248
+ * `QueryTemplate` returns template by the template name;
213
249
  * `CreateNode` crates new node in the repository;
214
- * `QueryTemplate` provides text of the template provided as parameter.
250
+ * `RenderNode` returns text rendered by ERB.
215
251
 
216
- The first part of each repository related task is to get repository assembly. It can be performed through `NodeRepository#assemble` or `QueryAssembly.call`. Each of these methods returns Node that provides [Enumerable](https://ruby-doc.org/core-2.6.5/Enumerable.html) interface.
252
+ The first part of each repository related task is to get repository assembly. It can be performed through `NodeRepository#assemble` or `LoadAssembly.call()`. Each of these methods returns Node that provides [Enumerable](https://ruby-doc.org/core-2.6.5/Enumerable.html) interface.
217
253
 
218
- Let's invent some advanced scenario. Assume that you develop a "User requirements document" and the project policy requires that each user requirement must have the parameter called `originator`. You can write the policy as followed:
254
+ Let's see an example. Assume that you are developing a "User requirements document" and the project policy requires that each user requirement must have the parameter called `originator`. You can write the policy as followed:
219
255
 
220
256
  ```ruby
221
257
  require 'clerq'
222
- include Clerk::Interactors
258
+ include Clerq::Services
223
259
 
224
260
  # supposed you have something like user requirements document
225
- node = QueryAssembly.("node.title == 'User requirements'")
261
+ node = LoadAssembly.()
262
+ node = QueryNode.(node: node, query: "node.title == 'User requirements'")
226
263
  miss = node.drop(1).select{|n| n[:originator].empty? }
227
264
  unless miss.empty?
228
- errmsg = "`Originator` is missed for the next nodes:\n"
265
+ errmsg = "`Originator` is missed for the following nodes:\n"
229
266
  errmsg << miss.map(&:id).join(', ')
230
267
  raise Error, errmsg
231
268
  end
232
269
  ```
233
270
 
271
+ Instead of adding extra scripts files somewhere in the project, you can write tasks in `<project>.thor` (see [Automating](#automating) section for details.)
272
+
234
273
  #### Root Node
235
274
 
236
275
  A hierarchy starts form root node and Clerq provides the root node with parameter `title` specified in `clerq.yml` file. The subject is a bit tricky actually and there are few extra considerations I try to explain below (and you can always see tests)
@@ -241,34 +280,83 @@ When you have a few root nodes in your repository, those become direct childs o
241
280
 
242
281
  The following example does not provide root node and it causes adding root node from `clerq.yml`.
243
282
 
244
- ```
283
+ ```markdown
245
284
  # User requirements
246
285
  # Functional requirements
247
286
  ```
248
287
 
249
- But this one provides, and root node will be `Product SRS` according to rule 1.
288
+ But this one provides, and the root node will be `Product SRS`.
250
289
 
251
- ```
290
+ ```markdown
252
291
  # Product SRS
253
292
  ## User requirements
254
293
  ## Functional requirements
255
294
  ```
256
295
 
257
- The QueryAssembly.call(query) follow similar logic
296
+ The QueryAssembly follows the similar logic
258
297
 
259
298
  * When query result is empty, the Clerq will provide result with QueryNullNode (node.title == `Query`, node[:query] == QUERY_STRING)
260
299
  * When query result contains single node, it becomes a root query node.
261
300
  * When query result contains more than one, those becomes a child of root query node.
262
301
 
302
+ ### Automating
303
+
304
+ The Clerq creates `<project>.thor` where you can place your project-specific tasks. It is a standard [Thor](https://github.com/erikhuda/thor) that brings you all script automation power through CLI and to dive deeper just spend a few minutes reading [the poject wiki](https://github.com/erikhuda/thor/wiki).
305
+
306
+ Let's move the code from [Scripting](#scripting) section to the `<project>.thor` file:
307
+
308
+ ```ruby
309
+ require 'clerq'
310
+ include Clerq::Services
311
+
312
+ class MyDocument < Thor
313
+ namespace :mydoc
314
+
315
+ no_commands {
316
+ def stop_on_error!(errmsg)
317
+ raise Thor::Error, errmsg
318
+ end
319
+ }
320
+
321
+ desc 'check_originator', 'Check :originator'
322
+ def check_originator
323
+ node = LoadAssembly.()
324
+ node = QueryAssembly.(node: node, query: "node.title == 'User requirements'")
325
+ miss = node.drop(1).select{|n| n[:originator].empty? }
326
+ unless miss.empty?
327
+ errmsg = "`Originator` is missed for the following nodes:\n"
328
+ errmsg << miss.map(&:id).join(', ')
329
+ stop_on_error!(errmsg)
330
+ end
331
+ end
332
+ end
333
+ ```
334
+
335
+ And then you can run the task by
336
+
337
+ $ thor mydoc:check_originator
338
+
339
+ This example is just very basic and your automation scripts could be much more complex.
340
+
341
+ Another quick example is the [clerq.thor](https://github.com/nvoynov/clerq/blob/master/clerq.thor) file that was created just to overcome handling curly bracket `{{}}` in Jekyll and now I run `thor clerq:src:docs` every time after changing this file.
342
+
263
343
  ### Templating
264
344
 
265
- The Clerq provides the ability to precise adjusting the output for `clerq build` command by erb-templates and gives you two basic templates from the box.
345
+ The output of the `clerq build` command can be precisely adjusted by modifying the corresponding "erb" template.
346
+
347
+ One can see the standard template in [default.md.erb](https://github.com/nvoynov/clerq/blob/master/lib/assets/tt/default.md.erb). It produced output in [Pandoc's Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown) format and supports the following macros in node body:
266
348
 
267
- * [default.md.erb](https://github.com/nvoynov/clerq/blob/master/lib/assets/tt/default.md.erb) that just combines all nodes to one markdown document;
268
- * [pandoc.md.erb](https://github.com/nvoynov/clerq/blob/master/lib/assets/tt/pandoc.md.erb) is more advanced, it produces [Pandoc's Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown) and provides three followed macros for node body:
269
- * `{{@@list}}` - replaces the macro with the list of child requirements;
270
- * `{{@@tree}}` - replaces the macro with the tree of child requirements;
271
- * `{{@@skip}}` - skip all content inside the brackets.
349
+ * `{{@@list}}` - replaces the macro with the list of child nodes;
350
+ * `{{@@tree}}` - replaces the macro with the tree of child nodes;
351
+ * `{{@@eval}}` - eval ruby code inside the brackets;
352
+ * `{{@@skip}}` - skip all content inside the brackets.
353
+
354
+ ### Publishing
355
+
356
+ In addition to the `clerq build` command one can find an example of basic documents management tasks in the [lib/clerq_doc.thor](https://github.com/nvoynov/clerq/blob/master/lib/assets/lib/clerq_doc.thor) (it will be placed in new project `lib` folder). You can find there two example of commands that you can start your own publishing automation.
357
+
358
+ * `thor clerq:doc:publish` will create `<project>.docx` and `<project>.html`;
359
+ * `thor clerq:doc:grab` will import provided document into the current project repository.
272
360
 
273
361
  ## Known issues
274
362
 
@@ -282,14 +370,10 @@ The one issue I certain in is when you are using different version of thor, your
282
370
 
283
371
  Use modern text editor that provides projects tree. like Atom, Sublime, etc.
284
372
 
285
- Hold your projects in Git
373
+ Hold your projects in Git.
286
374
 
287
375
  Use pandoc for generating output in different formats
288
376
 
289
- ### MarkupNode
290
-
291
- Don't like the current dirty solution with templates and incorporated MarkupNode that does all that stuff with macro. It is the first attempt to provide template that can skipp comments
292
-
293
377
  ### Several artifacts
294
378
 
295
379
  Because Clerq has `-q/--query QUERY_STRING` option you can be interested in developing several different artifacts in one project.
data/Rakefile CHANGED
@@ -5,6 +5,7 @@ Rake::TestTask.new(:test) do |t|
5
5
  t.libs << "test"
6
6
  t.libs << "lib"
7
7
  t.test_files = FileList["test/**/*_spec.rb"]
8
+ t.warning = false
8
9
  end
9
10
 
10
11
  task :default => :test
data/clerq.gemspec CHANGED
@@ -36,9 +36,9 @@ Gem::Specification.new do |spec|
36
36
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
37
  spec.require_paths = ["lib"]
38
38
 
39
- spec.add_development_dependency "bundler", "~> 1.17"
40
- spec.add_development_dependency "rake", "~> 10.0"
41
- spec.add_development_dependency "minitest", "~> 5.0"
39
+ spec.add_development_dependency "bundler", "~> 2.2.3"
40
+ spec.add_development_dependency "rake", "~> 13.0"
41
+ spec.add_development_dependency "minitest", "~> 5.14.2"
42
42
 
43
- spec.add_runtime_dependency "thor", "~> 0.20.3"
43
+ spec.add_runtime_dependency "thor", "~> 1.0.1"
44
44
  end
data/clerq.thor ADDED
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'thor'
4
+
5
+ class ClerqSrc < Thor
6
+ include Thor::Actions
7
+ namespace 'clerq:src'.to_sym
8
+
9
+ desc 'docs', 'Prepare docs'
10
+ def docs
11
+ # to wrap all '{{}}' of README.md with `{% raw %} <> {% endraw %}
12
+ text = File.read(SOURCE)
13
+ SUBS.each{|patt, subs|
14
+ text.scan(patt).uniq.each{|e| text.gsub!(e, subs.call(e))}
15
+ }
16
+ File.write(TARGET, text)
17
+ say "'#{TARGET}' created!"
18
+ end
19
+
20
+ SOURCE = 'README.md'
21
+ TARGET = 'docs/README.md'
22
+ REX1, REX2 = /`{{[\s\S]*?}}`/, /```markdown[\s\S]*?```/
23
+ SUBS = {}.tap do |curly|
24
+ curly[REX1] = lambda {|e| "{% raw %}#{e}{% endraw %}" }
25
+ curly[REX2] = lambda {|e| "{% raw %}\n#{e}\n{% endraw %}" }
26
+ end.freeze
27
+
28
+ end
data/docs/README.md ADDED
@@ -0,0 +1,415 @@
1
+ # Clerq
2
+
3
+ __What is Clerq?__
4
+
5
+ The Clerq is a toolbox for manipulating the hierarchy of text data placed in separate markdown files. It implements three basic ideas:
6
+
7
+ 1. Text data repository in file system, based on markdown files with few extra conventions.
8
+ 2. Ruby gem that provides access to the text hierarchy from the repository.
9
+ 3. Basic CLI to manage the repository and compile the text data to documents based on erb-templates.
10
+
11
+ __What for?__
12
+
13
+ The Clerq is suitable for writing thick structured texts. The initial purpose for the system was the "requirements management in file system" and it supposed to help in writing stuff like Vision, RFP, URD, SRS, SAD, and deriving various requirements based artifacts. But now it seems much wider.
14
+
15
+ ## Installation
16
+
17
+ Install it yourself as:
18
+
19
+ $ gem install clerq
20
+
21
+ ## Promo
22
+
23
+ ![Clerq Promo Project](promo.png)
24
+
25
+ Inside Clerq there is a demo project that was created and is still used to develop Clerq itself and its script-extensions. You can see the project [here](https://github.com/nvoynov/clerq/tree/master/lib/assets/promo) ([requirements sources](https://github.com/nvoynov/clerq/tree/master/lib/assets/promo/src) and produced documents [Clerq SRS.md](https://github.com/nvoynov/clerq/blob/master/lib/assets/promo/bin/Clerq%20SRS.md), [Clerq SRS.docx](https://github.com/nvoynov/clerq/blob/master/lib/assets/promo/bin/Clerq%20SRS.docx))
26
+
27
+ I am sure this project will be useful when you get to know the product. So, I propose to open it now and look inside as you move forward. Do the following in your console:
28
+
29
+ $ clerq new promo
30
+ $ cd promo
31
+ $ clerq promo
32
+ $ atom .
33
+ $ thor list
34
+
35
+ ## Usage
36
+
37
+ The Clerq is entirely based on one single domain entity `Node` that represents a node of tree hierarchy and provides `id`, `title`, `body`, and `metadata` attributes. It supposes the following simple workflow:
38
+
39
+ * you create files with text content,
40
+ * and manipulate the data by scripts.
41
+
42
+ ### Project
43
+
44
+ The Clerq project lives in the following folders structure that will be created by `clerq new <project>`:
45
+
46
+ * `bin/` - for output documents;
47
+ * `bin/assets` - for assets;
48
+ * `knb/` - knowledge base;
49
+ * `lib/` - place for extra Ruby code;
50
+ * `src/` - source data repository;
51
+ * `tt/` - templates;
52
+ * `<project>.thor` - see [Scripting](#scripting);
53
+ * `clerq.yml` - project settings;
54
+ * `README.md`.
55
+
56
+ ### Writing
57
+
58
+ The Clerq reads nodes from a set of separate files and assembles it to a single hierarchy. There are a few conventions for a separate file that will become a part of hierarchy.
59
+
60
+ #### Files
61
+
62
+ The first convention is the scheme how a markdown content becomes the `Node` entity.
63
+
64
+ {% raw %}
65
+ ```markdown
66
+ # [p2] Part two
67
+ {{parent: top}}
68
+
69
+ Body
70
+ ```
71
+ {% endraw %}
72
+
73
+ Where
74
+
75
+ * `#` familiar markdown header that indicates a new `node`;
76
+ * `[p1]` is an optional identifier that becomes `node.id`;
77
+ * `Part two` is an optional `node.title`;
78
+ * {% raw %}`{{parent: top}}`{% endraw %} is an optional metadata section that becomes `node.meta`;
79
+ * and finally `Body` is an optional `node.body`.
80
+
81
+ {% raw %}
82
+ ```markdown
83
+ # Part two
84
+ {{id: p1, parent: top}}
85
+
86
+ Body
87
+ ```
88
+ {% endraw %}
89
+
90
+ Every new header (`#`) at any level indicates a new node. When a file contains headers of different levels, the nodes will be created in a natural hierarchy based on header levels. So as the result of reading the content below, the Clerq will create the natural hierarchy with root node `Top` that holds two child nodes `First` and `Second`.
91
+
92
+ {% raw %}
93
+ ```markdown
94
+ # Top
95
+ ## First
96
+ ## Second
97
+ ```
98
+ {% endraw %}
99
+
100
+ One more extra thing is links. You can place links to other nodes in the body section of the file content by using `[[<id>]]` macro. It can be handled in templates.
101
+
102
+ #### IDs
103
+
104
+ To be able to build a hierarchy or to refer to other nodes, one needs each node to have its unique id. And you can pass it straight into markdown header `# [node id] node title` or provide it through {% raw %}`{{id: }}`{% endraw %}.
105
+
106
+ ID can start with one dot, like `[.suffix]`, and clerq will build the node id as `node.parent_id + node.id`.
107
+
108
+ When and ID is not provided, the Clerq will generate it automatically. Let's see the example of node:
109
+
110
+ {% raw %}
111
+ ```markdown
112
+ # User requirements
113
+ ## Requirement 1
114
+ ## Requirement 2
115
+ # Function requirements
116
+ ## [cm] Components
117
+ ### [.fm] File manager
118
+ ### Logger
119
+ ```
120
+ {% endraw %}
121
+
122
+ According to rules mentioned above the example will be translated as followed:
123
+
124
+ {% raw %}
125
+ ```markdown
126
+ # [01] User requirements
127
+ ## [01.01] Requirement 1
128
+ ## [01.02] Requirement 2
129
+ # [02] Function requirements
130
+ ## [cm] Components
131
+ ### [cm.fm] File manager
132
+ ### [cm.01] Logger
133
+ ```
134
+ {% endraw %}
135
+
136
+ #### Meta
137
+
138
+ The excerpt, the text in brackets {% raw %}`{{ }}`{% endraw %} that follows by the header, contains node attributes. And the second convention mentioned in [Writing](#writing) section is the followed magic metadata attributes that specify parameters of a hierarchy:
139
+
140
+ 1. `id: <id>` specifies id through metadata; when in provided together with `# [<id>]`, the last has priority;
141
+ 2. `parent: <id>` indicates that the node belongs to a node with specified `id`;
142
+ 3. `order_index: <id1> <id2>` indicates that child nodes must be lined up in specified order.
143
+
144
+ You can place in metadata any simple string that suitable for providing additional information like status, originator, author, priority, etc. E.g.
145
+
146
+ {% raw %}
147
+ ```markdown
148
+ # [r.1]
149
+ {{parent: r, status: draft}}
150
+
151
+ # [r.2]
152
+ {{parent: r
153
+ }}
154
+
155
+ # [r.3]
156
+ {{
157
+ parent: r}}
158
+ ```
159
+ {% endraw %}
160
+
161
+ #### Assets
162
+
163
+ When you want to provide some assets or links to something outside the repository you can provide the link to the assets. Put the asset in the `bin/assets` folder and specify the link.
164
+
165
+ {% raw %}
166
+ ```markdown
167
+ # [ent] Entities
168
+
169
+ The following picture shows something
170
+
171
+ ![Image](assets/er.png)
172
+ ```
173
+ {% endraw %}
174
+
175
+ ### CLI
176
+
177
+ Clerq provides CLI that is based on Thor, so all standard thor features are supported. To print all Clerq commands type `$ clerq help` in your console. To see the list of all the project-specific commands type `thor help <project>`.
178
+
179
+ #### Create new project
180
+
181
+ To create a new project run `new` command:
182
+
183
+ $ clerq new <project_name>
184
+
185
+ #### Create new file
186
+
187
+ The simplest way of adding new items to the project is to add a new file to the `src` directory. Of course, Clerq also provides the command `node` that can create template-based files:
188
+
189
+ $ clerq node ID [TITLE] [-t TEMPLATE]
190
+
191
+ __Assets__
192
+
193
+ If you are using images or other assets, you should place it to `bin/assets` directory and write markdown link like `![img](assets/img.png)`
194
+
195
+ __Templates__
196
+
197
+ You also can prepare your own templates it `tt` folder and provide template through `-t/--template` option. The content of the template will be placed on the created file.
198
+
199
+ #### Check repository
200
+
201
+ Because of lots of handwriting there can be some specific errors in repository. The most obvious are:
202
+
203
+ * non-unique identifiers;
204
+ * links to and id that does not exist:
205
+ * for `parent` attribute;
206
+ * in `order_index`;
207
+ * in `body`.
208
+
209
+ The system provides command `clerq check` that will check the repository for these kinds of errors.
210
+
211
+ $ clerq check
212
+
213
+ #### Build project
214
+
215
+ Clerq provides the ability to combine all the text data from the project repository and create the final document. To create such document you can use `clerq build` command:
216
+
217
+ $ clerq build
218
+
219
+ It will create final document with default file name, title, and by default erb template. These default values are defined in `clerq.yml` and you should change it according to your aim.
220
+
221
+ Default values of final document parameters are:
222
+
223
+ * `document: <project_name>`;
224
+ * `template: default.md.erb`;
225
+ * `title: <project_name>`.
226
+
227
+ You also can specify these settings through `clerq build` options:
228
+
229
+ * `-t/--template TEMPLATE` provides the ability to specify template;
230
+ * `-o/--output FILE_NAME` provides the ability to specify output file name.
231
+
232
+ __Queries__
233
+
234
+ Clerq provides the ability to query data that match query criteria. To query data you should use `-q/--query QUERY_STRING` option where `QUERY_STRING` is ruby code that will test if each node matches the `QUERY_STRING`. For example, `node.tile == 'Functional requirements'` or `node.id == 'us'`.
235
+
236
+ #### Print TOC
237
+
238
+ Sometimes it helpful to check repository structure by `clerq toc` command. The command also supports `-q/--query QUERY_STRING` option.
239
+
240
+ ### Scripting
241
+
242
+ The section assumes that you are familiar with Ruby or some other programming language.
243
+
244
+ Using the basic commands described in [CLI](#cli) section gives you just the ability to create final documents or other output. But this is just the tip of the iceberg, just the beginning, and you can do much more than that with Clerq.
245
+
246
+ A usual scenario will consist of two simple steps:
247
+
248
+ 1. Get data hierarchy from the repository.
249
+ 2. Do some processing of the hierarchy.
250
+
251
+ #### Node class
252
+
253
+ The [Writing](#writing) section provides the basic knowledge to understand Clerq, and now it is the right time to see the [Node class](https://github.com/nvoynov/clerq/blob/master/lib/clerq/entities/node.rb). It implements the Composite pattern.
254
+
255
+ #### Services
256
+
257
+ Clerq provides the following main service objects:
258
+
259
+ * `LoadAssembly` loads whole repository to Node class;
260
+ * `CheckAssembly` checks the assembly for errors (ids and links);
261
+ * `QueryNode` provides ability to query nodes from assembly;
262
+ * `QueryTemplate` returns template by the template name;
263
+ * `CreateNode` crates new node in the repository;
264
+ * `RenderNode` returns text rendered by ERB.
265
+
266
+ The first part of each repository related task is to get repository assembly. It can be performed through `NodeRepository#assemble` or `LoadAssembly.call()`. Each of these methods returns Node that provides [Enumerable](https://ruby-doc.org/core-2.6.5/Enumerable.html) interface.
267
+
268
+ Let's see an example. Assume that you are developing a "User requirements document" and the project policy requires that each user requirement must have the parameter called `originator`. You can write the policy as followed:
269
+
270
+ ```ruby
271
+ require 'clerq'
272
+ include Clerq::Services
273
+
274
+ # supposed you have something like user requirements document
275
+ node = LoadAssembly.()
276
+ node = QueryNode.(node: node, query: "node.title == 'User requirements'")
277
+ miss = node.drop(1).select{|n| n[:originator].empty? }
278
+ unless miss.empty?
279
+ errmsg = "`Originator` is missed for the following nodes:\n"
280
+ errmsg << miss.map(&:id).join(', ')
281
+ raise Error, errmsg
282
+ end
283
+ ```
284
+
285
+ Instead of adding extra scripts files somewhere in the project, you can write tasks in `<project>.thor` (see [Automating](#automating) section for details.)
286
+
287
+ #### Root Node
288
+
289
+ A hierarchy starts form root node and Clerq provides the root node with parameter `title` specified in `clerq.yml` file. The subject is a bit tricky actually and there are few extra considerations I try to explain below (and you can always see tests)
290
+
291
+ When your repository stills empty, the Clerq will provide you with the root node. From one point it resembles the NullObject.
292
+
293
+ When you have a few root nodes in your repository, those become direct childs of the root node. But when your repository contains single root node, the Clerq will return the single node as root node.
294
+
295
+ The following example does not provide root node and it causes adding root node from `clerq.yml`.
296
+
297
+ {% raw %}
298
+ ```markdown
299
+ # User requirements
300
+ # Functional requirements
301
+ ```
302
+ {% endraw %}
303
+
304
+ But this one provides, and the root node will be `Product SRS`.
305
+
306
+ {% raw %}
307
+ ```markdown
308
+ # Product SRS
309
+ ## User requirements
310
+ ## Functional requirements
311
+ ```
312
+ {% endraw %}
313
+
314
+ The QueryAssembly follows the similar logic
315
+
316
+ * When query result is empty, the Clerq will provide result with QueryNullNode (node.title == `Query`, node[:query] == QUERY_STRING)
317
+ * When query result contains single node, it becomes a root query node.
318
+ * When query result contains more than one, those becomes a child of root query node.
319
+
320
+ ### Automating
321
+
322
+ The Clerq creates `<project>.thor` where you can place your project-specific tasks. It is a standard [Thor](https://github.com/erikhuda/thor) that brings you all script automation power through CLI and to dive deeper just spend a few minutes reading [the poject wiki](https://github.com/erikhuda/thor/wiki).
323
+
324
+ Let's move the code from [Scripting](#scripting) section to the `<project>.thor` file:
325
+
326
+ ```ruby
327
+ require 'clerq'
328
+ include Clerq::Services
329
+
330
+ class MyDocument < Thor
331
+ namespace :mydoc
332
+
333
+ no_commands {
334
+ def stop_on_error!(errmsg)
335
+ raise Thor::Error, errmsg
336
+ end
337
+ }
338
+
339
+ desc 'check_originator', 'Check :originator'
340
+ def check_originator
341
+ node = LoadAssembly.()
342
+ node = QueryAssembly.(node: node, query: "node.title == 'User requirements'")
343
+ miss = node.drop(1).select{|n| n[:originator].empty? }
344
+ unless miss.empty?
345
+ errmsg = "`Originator` is missed for the following nodes:\n"
346
+ errmsg << miss.map(&:id).join(', ')
347
+ stop_on_error!(errmsg)
348
+ end
349
+ end
350
+ end
351
+ ```
352
+
353
+ And then you can run the task by
354
+
355
+ $ thor mydoc:check_originator
356
+
357
+ This example is just very basic and your automation scripts could be much more complex.
358
+
359
+ Another quick example is the [clerq.thor](https://github.com/nvoynov/clerq/blob/master/clerq.thor) file that was created just to overcome handling curly bracket {% raw %}`{{}}`{% endraw %} in Jekyll and now I run `thor clerq:src:docs` every time after changing this file.
360
+
361
+ ### Templating
362
+
363
+ The output of the `clerq build` command can be precisely adjusted by modifying the corresponding "erb" template.
364
+
365
+ One can see the standard template in [default.md.erb](https://github.com/nvoynov/clerq/blob/master/lib/assets/tt/default.md.erb). It produced output in [Pandoc's Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown) format and supports the following macros in node body:
366
+
367
+ * {% raw %}`{{@@list}}`{% endraw %} - replaces the macro with the list of child nodes;
368
+ * {% raw %}`{{@@tree}}`{% endraw %} - replaces the macro with the tree of child nodes;
369
+ * {% raw %}`{{@@eval}}`{% endraw %} - eval ruby code inside the brackets;
370
+ * {% raw %}`{{@@skip}}`{% endraw %} - skip all content inside the brackets.
371
+
372
+ ### Publishing
373
+
374
+ In addition to the `clerq build` command one can find an example of basic documents management tasks in the [lib/clerq_doc.thor](https://github.com/nvoynov/clerq/blob/master/lib/assets/lib/clerq_doc.thor) (it will be placed in new project `lib` folder). You can find there two example of commands that you can start your own publishing automation.
375
+
376
+ * `thor clerq:doc:publish` will create `<project>.docx` and `<project>.html`;
377
+ * `thor clerq:doc:grab` will import provided document into the current project repository.
378
+
379
+ ## Known issues
380
+
381
+ ### Thor version
382
+
383
+ The one issue I certain in is when you are using different version of thor, your custom scripts won't work.
384
+
385
+ ## Some considerations
386
+
387
+ ### Some obvious things
388
+
389
+ Use modern text editor that provides projects tree. like Atom, Sublime, etc.
390
+
391
+ Hold your projects in Git.
392
+
393
+ Use pandoc for generating output in different formats
394
+
395
+ ### Several artifacts
396
+
397
+ Because Clerq has `-q/--query QUERY_STRING` option you can be interested in developing several different artifacts in one project.
398
+
399
+ I was considering such an example to develop all software project documents in one clerq project but decided that it is more properly to develop one single artifact per project because usually, each artifact has its own develop-review-release cycle.
400
+
401
+ Also, I was considering to add some kind of a "top" project that is just a wrapper for individual projects inside (each of them is the clerq project, and the top project just provides a specific set of commands.) I was speculating about some kind of shared content and tracing nodes between different artifacts. But for the moment I have no full-fledged vision.
402
+
403
+ ## Development
404
+
405
+ The project is bundled, so after checking out the repo, run `bundle` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
406
+
407
+ 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 [rubygems.org](https://rubygems.org).
408
+
409
+ ## Contributing
410
+
411
+ Bug reports and pull requests are welcome on GitHub at https://github.com/nvoynov/clerq.
412
+
413
+ ## License
414
+
415
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).