marko 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +12 -0
  3. data/.rubocop.yml +45 -0
  4. data/CHANGELOG.md +54 -1
  5. data/Dockerfile +11 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +24 -35
  8. data/Rakefile +2 -6
  9. data/exe/marko +4 -20
  10. data/lib/basic.rb +27 -0
  11. data/lib/marko/chain.rb +44 -0
  12. data/lib/marko/cli.rb +119 -121
  13. data/lib/marko/config.rb +30 -20
  14. data/lib/marko/errors.rb +38 -0
  15. data/lib/marko/model/markup.rb +33 -0
  16. data/lib/marko/model/topic.rb +126 -0
  17. data/lib/marko/model/tree_node.rb +34 -0
  18. data/lib/marko/model.rb +10 -0
  19. data/lib/marko/parser/metadata.rb +28 -0
  20. data/lib/marko/parser/source.rb +52 -0
  21. data/lib/marko/parser/topic.rb +33 -0
  22. data/lib/marko/parser.rb +8 -19
  23. data/lib/marko/renderers/artifact.rb +29 -0
  24. data/lib/marko/renderers/content.rb +37 -0
  25. data/lib/marko/renderers/link.rb +19 -0
  26. data/lib/marko/renderers/metadata.rb +34 -0
  27. data/lib/marko/renderers/nested_list.rb +21 -0
  28. data/lib/marko/renderers/nested_tree.rb +22 -0
  29. data/lib/marko/renderers/renderer.rb +17 -0
  30. data/lib/marko/renderers/title.rb +16 -0
  31. data/lib/marko/renderers/topic.rb +24 -0
  32. data/lib/marko/renderers/url.rb +16 -0
  33. data/lib/marko/renderers.rb +17 -0
  34. data/lib/marko/scanner.rb +39 -0
  35. data/lib/marko/tasks/assemble.rb +52 -0
  36. data/lib/marko/tasks/compile.rb +19 -0
  37. data/lib/marko/tasks/load.rb +13 -0
  38. data/lib/marko/tasks/parse.rb +27 -0
  39. data/lib/marko/tasks/scan.rb +18 -0
  40. data/lib/marko/tasks/validate.rb +32 -0
  41. data/lib/marko/tasks.rb +13 -0
  42. data/lib/marko/validators/lost_index.rb +21 -0
  43. data/lib/marko/validators/lost_links.rb +25 -0
  44. data/lib/marko/validators/lost_parent.rb +21 -0
  45. data/lib/marko/validators/non_unique_id.rb +23 -0
  46. data/lib/marko/validators.rb +11 -0
  47. data/lib/marko/version.rb +1 -3
  48. data/lib/marko.rb +11 -35
  49. metadata +47 -54
  50. data/Gemfile +0 -10
  51. data/Gemfile.lock +0 -22
  52. data/lib/assets/demo/README.md +0 -13
  53. data/lib/assets/demo/src/fr/assemble.md +0 -27
  54. data/lib/assets/demo/src/fr/compile.md +0 -25
  55. data/lib/assets/demo/src/fr/markup.md +0 -111
  56. data/lib/assets/demo/src/fr/storage.md +0 -16
  57. data/lib/assets/demo/src/fr/treenode.md +0 -34
  58. data/lib/assets/demo/src/index.md +0 -34
  59. data/lib/assets/demo/src/intro.md +0 -98
  60. data/lib/assets/demo/src/ui/cli.md +0 -26
  61. data/lib/assets/demo/src/ui/gem.md +0 -14
  62. data/lib/assets/demo/src/ur/uc.create.project.md +0 -8
  63. data/lib/assets/demo/src/ur/uc.general.flow.md +0 -14
  64. data/lib/assets/init/README.md +0 -61
  65. data/lib/assets/init/Rakefile +0 -100
  66. data/lib/assets/init/tt/artifact.md.tt +0 -3
  67. data/lib/marko/artifact.rb +0 -3
  68. data/lib/marko/assembler.rb +0 -82
  69. data/lib/marko/compiler.rb +0 -16
  70. data/lib/marko/gadgets/pluggable.rb +0 -55
  71. data/lib/marko/gadgets/sentry.rb +0 -66
  72. data/lib/marko/gadgets/service.rb +0 -52
  73. data/lib/marko/gadgets.rb +0 -3
  74. data/lib/marko/loader.rb +0 -38
  75. data/lib/marko/markup/compiler.rb +0 -36
  76. data/lib/marko/markup/decorator.rb +0 -65
  77. data/lib/marko/markup/macro.rb +0 -176
  78. data/lib/marko/markup/parser.rb +0 -122
  79. data/lib/marko/markup/storage.rb +0 -100
  80. data/lib/marko/markup/validator.rb +0 -101
  81. data/lib/marko/markup.rb +0 -24
  82. data/lib/marko/services/assemble.rb +0 -16
  83. data/lib/marko/services/compile.rb +0 -30
  84. data/lib/marko/services.rb +0 -2
  85. data/lib/marko/storage.rb +0 -36
  86. data/lib/marko/tree_node.rb +0 -128
  87. data/lib/marko/validator.rb +0 -19
  88. data/marko.gemspec +0 -44
@@ -1,111 +0,0 @@
1
- # Source Markup
2
- {{id: .markup, parent: fr}}
3
-
4
- The main and only entity in the system is [[fr.treenode]]. The system shall provide the following abilities for the entity:
5
-
6
- @@list
7
-
8
- ## Node Markup
9
- {{id: .node}}
10
-
11
- The system shall support the following node markup.
12
-
13
- ```markdown
14
- # <title>
15
- {{\<meta\>}}
16
- \<body\>
17
- ```
18
-
19
- Where:
20
-
21
- - Each node starts from Markdown header mark `#`.
22
- - The header mark can be followed by node title.
23
- - The next line _might_ contain metadata block:
24
- - that starts from `{{` and finishes with `}}`;
25
- - that can be one or multiline string.
26
- - The next lines tile the end of file or next header mark `#` are considered as node body.
27
-
28
- ## Get Sources
29
-
30
- The system shall provide function to getting all sources files from project repository.
31
-
32
- @@todo define project repository
33
-
34
- ## Parse Source
35
-
36
- The system shall provide the function to parse source file.
37
-
38
- During the parsing process the system must record source information within the node parsed, such as origin file name and the number of line inside the origin where the node begins. This information must be stored inside metadata as [[fr.treenode.orig]].
39
-
40
- __Input__
41
-
42
- Parameter Type 0..* Description
43
- --------- ------ ---- -----------
44
- filename String 1 filename
45
-
46
- __Output__
47
-
48
- Parameter Type 0..* Description
49
- --------- ------ ---- -----------
50
- node Node 0..n node parsed
51
-
52
- ## Assemble Tree
53
-
54
- The system shall provide the function to assemble the artifact tree. The artifact tree is assembled based on [[fr.treenode.tree]].
55
-
56
- @@todo The assemblage algorithm, errors handler
57
-
58
- __Input__
59
-
60
- Parameter Type 0..* Description
61
- --------- ------ ---- -----------
62
- node Node 0..n node array
63
-
64
- __Output__
65
-
66
- Parameter Type 0..* Description
67
- --------- ------ ---- -----------
68
- node Node 1 root tree
69
-
70
- ## Inject Id
71
-
72
- The system shall provide each node with unique node Id.
73
-
74
- Some nodes can already have ids from source file, especially those that referenced as parent or child and placed in separate files. For those nodes that still have empty id, the system must generate auto id 0..99.
75
-
76
- For example, when the system has assembled the tree
77
-
78
- ```markdown
79
- # Artifact
80
- ## Introduction
81
- ### Purpose
82
- ### Scope
83
- # User Requirements #ur
84
- # Functional Requirements #fr
85
- ```
86
-
87
- and then generated id, the generated ids should be as follows:
88
-
89
- ```markdown
90
- # Artifact Title #00
91
- ## Introduction #01.01
92
- ### Purpose #01.01.01
93
- ### Scope #01.01.02
94
- # User Requirements #ur
95
- # Functional Requirements #fr
96
- ```
97
-
98
- __Input__
99
-
100
- Parameter Type 0..* Description
101
- --------- ------ ---- -----------
102
- root Node 1 root node
103
-
104
- ## Checking Tree
105
-
106
- The system shall provide the function to check assembled tree for errors related to assembling tree based on [[fr.treenode.tree]]. The system must check the following errors:
107
-
108
- - `duplicate id`, finds two or more nodes that share the same id;
109
- - `unknown parent`, finds nodes that have `parent` metadata, but parent not found in the tree;
110
- - `unknown index`, finds nodes with `order_index` metadata where one or more children in the index not found;
111
- - `unknown links`, finds nodes containing links but the links are not found.
@@ -1,16 +0,0 @@
1
- # Sources Storage
2
- {{id: .storage, parent: fr}}
3
-
4
- The system shall provide a storage for artifact sources. The storage must provide the following features:
5
-
6
- - Create a new project
7
- - Remove project
8
- - Get the list of project sources
9
- - Get project source
10
-
11
- @@skip
12
-
13
- At this stage only option will be developed - the filesystem storage. Other options that should be considered for future stages are
14
-
15
- - Database storage (SQL and NoSQL)
16
- - Confluence Wiki
@@ -1,34 +0,0 @@
1
- # TreeNode
2
- {{id: .treenode, parent: fr}}
3
-
4
- The system shall provide `Node` entity with the following properties that provide the following attributes:
5
-
6
- Property Type *..n Default Description
7
- --------- ------ ---- ------- -----------
8
- id String 1 "" Node identifier
9
- parent Node 1 null Parent node reference
10
- title String 1 "" Node title
11
- meta Hash 1 {} Node metadata
12
- body String 1 "" Node body
13
- items Node 0..n [] Child node reference
14
-
15
- ## Tree Metadata
16
- {{id: .tree}}
17
-
18
- To assemble the project artifact from nodes placed among several source files, the system shall provide the following optional tree metadata attributes:
19
-
20
- Attribute Type 0..n Description
21
- ----------- ------ ---- --------------
22
- id String 0..1 Unique node id
23
- parent String 0..1 Parent id
24
- order_index String 0..1 Children ids delimited by space
25
-
26
- ## Source Metadata
27
- {{id: .orig}}
28
-
29
- During source file parsing, the system must store the following node origin information:
30
-
31
- Attribute Type 0..n Description
32
- ----------- ------ ---- --------------
33
- origin String 1 Source filename
34
- lineno String 1 Number of line
@@ -1,34 +0,0 @@
1
- # Intro
2
- {{id: intro}}
3
-
4
- # Users
5
- {{id: usr}}
6
-
7
- The users of the system are different people who play for authoring various sorts of technical documentation. It might be a technical writer, business/systems analyst, developer, etc.
8
-
9
- # User Requirements
10
- {{id: ur, order_index: uc}}
11
-
12
- ## Use Cases
13
- {{id: uc, order_index: .create.project .general.flow}}
14
-
15
- # Functional Requirements
16
- {{id: fr, order_index: .treenode .markup .storage .assemble .compile}}
17
-
18
- # Interface Requirements
19
- {{id: ui, order_index: .cli .gem}}
20
-
21
- # Assumptions and Dependencies
22
- {{id: as}}
23
-
24
- ##
25
-
26
- The system requires a user interface for managing markup sources. It is assumed that users utilize any text editor of their choice.
27
-
28
- ##
29
-
30
- The system requires tools for collaboration on artifacts by several authors simultaneously. Because of the plain text nature of the markup sources, It is assumed using Git for managing the artifact sources repository.
31
-
32
- ##
33
-
34
- The system requires the compilation of artifacts into deliverables in form of well-supported formats like pdf, doc, etc. It is assumed using Pandoc for creating deliverables.
@@ -1,98 +0,0 @@
1
- # Purpose
2
- {{parent: intro}}
3
-
4
- The main purpose of this document is to provide a comprehensive demo project for Marko gem. The other technical purpose is to have Marko Sandbox for testing and development.
5
-
6
- # Problem
7
- {{parent: intro}}
8
-
9
- There are a few alternatives for authors who work on bulky software artifacts like requirements specification. They can apply one of the following tools
10
-
11
- @@todo find a few popular requirements management tools
12
- @@todo find a few popular Tex alternatives
13
-
14
- - a particular requirements management tool, like Doors
15
- - a Word Processor, like Microsoft Word, Libra Office, or Google Docs;
16
- - an elaborate publishing system, like Tex;
17
- - or just using a simple Wiki system, like Confluence or Redmine.
18
-
19
- A requirements management tool might seem to be the best choice there because it is tailored exactly for the required process. But it certainly will be a "hard way" from a cost and time perspective, an elaborate and expensive solution requiring personnel to be trained and vendor support.
20
-
21
- Although deliverable artifacts could be seen as a usual document structured and expressed in headers and paragraphs, the meaning of each of those can be different. So word processors and wiki systems might be the perfect choice for presenting artifact deliverables, but they lack of semantic fails for content development and management. The best of them provide a scripting language for document processing, but it is usually too complicated and again lacks particular entities' semantics (stakeholders, requirements, constraints, etc.)
22
-
23
- Designing documents of hundreds of pages in word processors brings some peculiar drawbacks. The software tends to become "bulky" in operating, consuming too many system resources and responding with delays; tend to be fragile with styles.
24
-
25
- __The problem of__ the lack of simple tools and approaches for writing software artifacts __affects__ technical writers who develop and manage the artifacts __the impact of which is__ they tend to choose a publishing tool or a word processor that does not fit well to work on software artifacts causing lots of manual work and maybe other confusing things like "bulky" documents __a successful solution would be__ the tool that will provide
26
-
27
- - a plain text markup for writing artifact items, that will be easy to read for humans, and processed by machines;
28
- - a "semantics" layer to distinguish artifact items (actors, requirements, etc.) from supported text
29
- - the ability to automate tasks based on processing content according to its semantic value;
30
- - the ability to build a convenient presentation of the artifact (pdf, doc, odt);
31
- - will not depend on OS platform and any proprietary format or software.
32
-
33
- @@skip
34
-
35
- It provides a statement summarizing the problem being solved by the project.
36
-
37
- __The problem of__ [describe the problem]
38
- __affects__ [the stakeholders affected by the problem]
39
- __the impact of which is__ [what is the impact of the problem?]
40
- __a successful solution would be__ [list some key benefits of a successful solution]
41
-
42
- # Product
43
- {{parent: intro}}
44
-
45
- @@todo redesign the product statement for "who" section
46
-
47
- __For__ authors of software artifacts __who__ need a reliable and repeatable process of managing big software artifacts __the__ Marko Markup Compiler is a free open source software __that__ brings a "docs-as-code" approach with efficient plain markup for artifact sources, @@todo templates, CLI, Rake ..
48
-
49
- @@skip
50
-
51
- __For__ [target customer]
52
- __Who__ [statement of the need or opportunity]
53
- __The__ [product name] is a [product category]
54
- __That__ [key benefit, compelling reason to buy]
55
- __Unlike__ [primary competitive alternative]
56
- __Our product__ [statement of primary differentiation]
57
-
58
- # Scope
59
- {{parent: intro}}
60
-
61
- The developing system will consist of
62
-
63
- - the simple plain markup for writing the artifact sources;
64
- - the repository of artifact sources;
65
- - the algorithm for assembling the artifact from sources;
66
- - the markup for templates for publishing the artifact;
67
- - the command line interface for compiling the artifact into deliverables based on the templates
68
- - the Ruby Gem that presents the artifact as the collection o items that can be easily visited for tasks automation;
69
- - the demo project that will help the customers to adopt the approach and design their own solutions based on the approach.
70
-
71
- # Definitions
72
- {{parent: intro}}
73
-
74
- CLI
75
-
76
- : Command-line interface
77
-
78
- ERB
79
-
80
- : Ruby Templating system
81
-
82
- # References
83
- {{parent: intro}}
84
-
85
- 1. [Markdown Guide](https://www.markdownguide.org/)
86
- 2. [Pandoc User's Guide](https://pandoc.org/MANUAL.html)
87
- 3. [Git User's Manual](https://git-scm.com/docs/user-manual.html)
88
-
89
- # Overview
90
- {{parent: intro}}
91
-
92
- The remaining sections of this document provide user- and functional requirements of the system.
93
-
94
- The [[usr]] chapter introduces users of the system.
95
-
96
- The next chapter [[ur]] introduces users requirements that establish the context for the functional requirements.
97
-
98
- The following chapter [[fr]] describes detailed requirements for functions and user interfaces.
@@ -1,26 +0,0 @@
1
- # Command-line interface
2
- {{id: .cli, parent: ui}}
3
-
4
- The system shall provide a command-line interface. The interface must provide the following commands:
5
-
6
- @@list
7
-
8
- ## Create a new project
9
-
10
- The system shall provide the `new PROJECT` command. When the user requests the `new PROJECT` command, the system
11
-
12
- - ensures that `PROJECT` folder does not exist or fails
13
- - creates `PROJECT` folder and copies required files for new project
14
- - reports the user about success
15
-
16
- ## Compile artifact
17
-
18
- The system shall provide the `compile [-t TEMPALTE] [-o FILENAME]` command. When the user requests the `compile` command, the system
19
-
20
- - ensures that current directory is `Marko Project` directory, or fails
21
- - load `template`,
22
- - load from the `TEMPLATE` parameter when provided
23
- - or load default template when not
24
- - creates `tree` by using [[fr.assemble]]
25
- - compiles the tree by [[fr.compile]].(`tree`, `template`, `filename`)
26
- - reports the user about success
@@ -1,14 +0,0 @@
1
- # Gem interface
2
- {{id: .gem, parent: ui}}
3
-
4
- The system shall provide Ruby Gem with the following functions
5
-
6
- @@list
7
-
8
- ## Marko.assemble
9
-
10
- @@todo define Marko.assemble
11
-
12
- ## Marko.compile
13
-
14
- @@todo define Marko.compile
@@ -1,8 +0,0 @@
1
- # Create a new project
2
- {{id: uc.create.project, parent: uc}}
3
-
4
- __Main Flow__
5
-
6
- 1. The user requests the system to create a new project passing a project folder for new project.
7
- 2. The system checks for project folder to be unique. When folder with the same name exists already, the system reports it to the user and the scenario is finished.
8
- 3. The system creates the project folder and furnish it with project structure.
@@ -1,14 +0,0 @@
1
- # General Clerq flow
2
- {{id: uc.general.flow, parent: uc}}
3
-
4
- __Prerequisites__
5
-
6
- 1. The user inside Marko project (see [[uc.create.project]])
7
-
8
- __Main Flow__
9
-
10
- 1. The user creates and makes changes to the sources of the project. [outside the system]
11
- 2. The user requests the system to `compile` the artifact.
12
- 3. The system assembles the artifact from source files.
13
- 4. The system checks the artifact and reports the errors to the user if any.
14
- 5. The system returns the assembled artifact.
@@ -1,61 +0,0 @@
1
- % Marko Demo Project
2
-
3
- Welcome to your new [Marko](https://github.com/nvoynov/clerq) project!
4
-
5
- # Structure
6
-
7
- This project has the following structure:
8
-
9
- - [bin/](bin/) - output folder
10
- - [bin/assets/](bin/assets/) - assets folder
11
- - [src/](src/) - markup sources
12
- - [tt/](tt/) - templates
13
- - [marko.yml](marko.yml) - project configuration
14
- - [Rakefile](Rakefile) - Rakefile
15
- - [README.md](README.md)
16
-
17
- # Interface
18
-
19
- Run `marko` command in your console to see basic command-line interface.
20
-
21
- Extend it yourself through Rakefile
22
-
23
- # Git Repository
24
-
25
- [Git How To](https://githowto.com/)
26
-
27
- Incorporates changes from a remote repository:
28
-
29
- git pull
30
-
31
- Create a new branch to start any activity with the repository:
32
-
33
- git branch <branch_name>
34
-
35
- Make changes and commit your work:
36
-
37
- git add .
38
- git commit -m "branch_name - commit description"
39
-
40
- When your changes finished, incorporate changes from the remote repository and merge the `master` branch to your `branch_name`:
41
-
42
- git checkout master
43
- git pull
44
- git checkout <branch_name>
45
- git merge master
46
-
47
- Resolve all conflicts and commit changes:
48
-
49
- git add .
50
- git commit -m "branch_name conflicts resolved"
51
-
52
- Merge your changes to the `master` branch:
53
-
54
- git checkout master
55
- git merge <branch_name>
56
-
57
- Push your changes to the remote repository:
58
-
59
- git push
60
-
61
- Create a merge request if you are not allowed to push to the `master` branch.
@@ -1,100 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'marko'
4
- require 'marko/markup'
5
-
6
- namespace :marko do
7
-
8
- # @todo pandoc: bin/arfifact.docx: openBinaryFile: permission denied (Permission denied)
9
- # Success! Find the artifact in bin/arfifact.docx
10
- #
11
- desc 'Publish the artifact'
12
- task :publish do
13
- output = 'bin/arfifact'
14
- `marko c -o #{output}.md`
15
- pandoc = `pandoc #{output}.md -o #{output}.docx`
16
- File.delete("#{output}.md")
17
- puts "Success! Find the artifact in #{output}.docx"
18
- end
19
-
20
- desc 'Print table of contents'
21
- task :toc, :query do |t, args|
22
- args.with_defaults(query: '')
23
- tree = Marko.assemble
24
- query = args.query
25
- unless query.empty?
26
- tree = tree.find_node(query)
27
- unless tree
28
- puts "Nothing to be printed!"
29
- return
30
- end
31
- tree.orphan!
32
- end
33
- tree.each do |n|
34
- if n.root?
35
- puts "% #{n.title}" if n.root?
36
- next
37
- end
38
- title = n.title.empty? ? n.id : n.title
39
- puts '#' * n.nesting_level + " #{title} ##{n.id}"
40
- end
41
- end
42
-
43
- desc 'Print @@todo'
44
- task :todo do
45
- tree = Marko.assemble
46
- tree.to_a.drop(1)
47
- .select{|n| n.body =~ /@@todo/}
48
- .each{|n|
49
- list = n.body
50
- .scan(/@@todo.*$/)
51
- .map{_1.sub(/@@todo/, '')}
52
- .map{" #{_1.strip}"}
53
- .join(?\n)
54
- puts n[:origin]
55
- puts list
56
- puts
57
- }
58
- end
59
-
60
- def datestamp
61
- Time.new.strftime('%Y%m%d')
62
- end
63
-
64
- def timestamp
65
- Time.new.to_s
66
- end
67
-
68
- desc 'Punch meeting munutes'
69
- task :mm, :extra do |t, args|
70
- args.with_defaults(extra: '')
71
- extra = args.extra
72
- Dir.mkdir('mm') unless Dir.exist?('mm')
73
- body = MINUTES % timestamp
74
- name = "minutes-#{datestamp}#{extra.empty? ? '' : ?_ + extra}"
75
- name = File.join('mm', name)
76
- errm = "Minutes exists already. Maybe you can provide [EXTRA]?"
77
- fail errm if File.exist?(name)
78
- File.write(name, body)
79
- end
80
-
81
- MINUTES = <<~EOF.freeze
82
- %% Meeting Minutes %s
83
-
84
- # Attendants
85
-
86
- 1.
87
- 2.
88
-
89
- # Questions
90
-
91
- 1.
92
- 2.
93
-
94
- # Decisions
95
-
96
- 1.
97
- 2.
98
- EOF
99
-
100
- end
@@ -1,3 +0,0 @@
1
- <%= @node.header %>
2
- <%= @node.meta %>
3
- <%= @node.body %>
@@ -1,3 +0,0 @@
1
- module Marko
2
- Artifact = Struct.new(:id, :title, :template, :filename)
3
- end
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "gadgets"
4
- require_relative "config"
5
- require_relative "loader"
6
- require_relative "tree_node"
7
-
8
- module Marko
9
-
10
- # The strategy for assembling sources into artifact tree
11
- class Assembler < Service
12
-
13
- class Failure # < StandardError
14
- attr_reader :errors
15
- def initialize(message, *errors)
16
- @errors = errors
17
- super(
18
- errors
19
- .map{|e| e.lines.map{|l| " #{l}"}.join }
20
- .unshift(message + ?\n)
21
- .join
22
- )
23
- end
24
- end
25
-
26
- # @return [TreeNode]
27
- def call
28
- @block.(:stage, 'loading sources') if @block
29
- buffer, errors = Loader.(&@block)
30
- fail Failure.new('markup parsing errors', *errors) if errors.any?
31
- @block.(:stage, 'tree assemblage') if @block
32
- tree = assemble(buffer)
33
- @block.(:stage, 'tree enrichment') if @block
34
- injectid(tree)
35
- @block.(:stage, 'tree validation') if @block
36
- errors = validate(tree)
37
- fail Failure.new('tree validation errors', *errors) if errors.any?
38
- tree
39
- end
40
-
41
- protected
42
-
43
- # @param buff [Array<TreeNode>]
44
- # @return [TreeNode]
45
- def assemble(buff)
46
- art = Marko.artifact
47
- TreeNode.new(art.title, id: '0').tap {|root|
48
- # @todo buff.inject(root, :<<) wrong but why?
49
- buff.each{|n| root << n}
50
- root.items
51
- .select{|node| node[:parent] && node[:parent] != node.parent_id}
52
- .each{|node|
53
- parent = root.find{|n| n.id == node[:parent]}
54
- next unless parent # is must be left under root
55
- parent << node
56
- node.delete_meta(:parent)
57
- root.delete_item(node)
58
- }
59
- }
60
- end
61
-
62
- def injectid(tree)
63
- counter = {}
64
- tree
65
- .select {|node| node.id.empty?}
66
- .each do |node|
67
- index = counter[node.parent] || 1
68
- counter[node.parent] = index + 1
69
- id = index.to_s.rjust(2, '0')
70
- id = '.' + id unless node.parent == tree
71
- node[:id] = id
72
- end
73
- end
74
-
75
- def validate(tree)
76
- validator = ValidatorPlug.plugged
77
- validator.(tree)
78
- end
79
-
80
- end
81
-
82
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "tree_node"
4
- require_relative "gadgets"
5
-
6
- module Marko
7
- class Compiler
8
- extend Pluggable
9
- def call(tree, template, filename, &block)
10
- @tree = MustbeTreeNode.(tree)
11
- @template = MustbeString.(template)
12
- @filename = MustbeString.(filename)
13
- @block = block
14
- end
15
- end
16
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Marko
4
- # Pluggable mixin serves for dependency injection
5
- #
6
- # @example
7
- # class Storage
8
- # extend Pluggable
9
- # def call
10
- # end
11
- # end
12
- #
13
- # StoragePort = Storage.port
14
- #
15
- # class SequelStorage < Storage
16
- # end
17
- #
18
- # StoragePort.plugged = SequelStorage.new
19
- #
20
- # require 'forwardable'
21
- # class Service
22
- # extend Forwardable
23
- # def_delegator :StoragePort, :plugged, :storage
24
- # def call
25
- # storage.call
26
- # end
27
- # end
28
- module Pluggable
29
-
30
- def plug
31
- klass = self
32
- Module.new {
33
- extend Plug;
34
- plug klass
35
- }
36
- end
37
-
38
- module Plug
39
- def plug(klass)
40
- @klass = klass
41
- end
42
-
43
- def plugged
44
- fail "unknown @klass" unless @klass
45
- @plugged ||= @klass.new
46
- end
47
-
48
- def plugged=(obj)
49
- fail ArgumentError.new("required an instance of #{@klass}"
50
- ) unless obj.is_a?(@klass)
51
- @plugged = obj
52
- end
53
- end
54
- end
55
- end