clerq 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +24 -0
- data/README.md +269 -0
- data/Rakefile +10 -0
- data/TODO.md +3 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/clerq.gemspec +44 -0
- data/exe/clerq +8 -0
- data/lib/assets/new/README.md.tt +75 -0
- data/lib/assets/new/clerq.thor.tt +15 -0
- data/lib/assets/new/clerq.yml.tt +4 -0
- data/lib/assets/new/content.md.tt +41 -0
- data/lib/assets/promo/README.md +40 -0
- data/lib/assets/promo/bin/Clerq SRS.docx +0 -0
- data/lib/assets/promo/bin/Clerq SRS.md +579 -0
- data/lib/assets/promo/bin/assets/promo_dark.png +0 -0
- data/lib/assets/promo/bin/assets/promo_light.png +0 -0
- data/lib/assets/promo/clerq.yml +3 -0
- data/lib/assets/promo/promo.thor +58 -0
- data/lib/assets/promo/src/clerq.md +82 -0
- data/lib/assets/promo/src/fr/cmp.node.md +14 -0
- data/lib/assets/promo/src/fr/cmp.repo.md +10 -0
- data/lib/assets/promo/src/fr/cmp.tt.md +20 -0
- data/lib/assets/promo/src/fr/cmp.writer.md +19 -0
- data/lib/assets/promo/src/fr/ent.md +32 -0
- data/lib/assets/promo/src/ui/cli/cli.bld.md +32 -0
- data/lib/assets/promo/src/ui/cli/cli.chk.md +17 -0
- data/lib/assets/promo/src/ui/cli/cli.hlp.md +14 -0
- data/lib/assets/promo/src/ui/cli/cli.new.md +20 -0
- data/lib/assets/promo/src/ui/cli/cli.opt.md +11 -0
- data/lib/assets/promo/src/ui/cli/cli.ver.md +4 -0
- data/lib/assets/promo/src/ui/ui.cli.md +8 -0
- data/lib/assets/promo/src/us/us.reader.md +8 -0
- data/lib/assets/promo/src/us/us.writer.md +79 -0
- data/lib/assets/tt/default.md.erb +64 -0
- data/lib/assets/tt/gitlab.md.erb +93 -0
- data/lib/assets/tt/pandoc.md.erb +88 -0
- data/lib/assets/tt/raw.md.erb +23 -0
- data/lib/clerq.rb +41 -0
- data/lib/clerq/cli.rb +129 -0
- data/lib/clerq/entities.rb +2 -0
- data/lib/clerq/entities/node.rb +135 -0
- data/lib/clerq/entities/template.rb +19 -0
- data/lib/clerq/gateways.rb +3 -0
- data/lib/clerq/gateways/gateway.rb +17 -0
- data/lib/clerq/gateways/in_files.rb +36 -0
- data/lib/clerq/gateways/in_memory.rb +35 -0
- data/lib/clerq/interactors.rb +5 -0
- data/lib/clerq/interactors/check_nodes.rb +81 -0
- data/lib/clerq/interactors/compile_nodes.rb +31 -0
- data/lib/clerq/interactors/create_node.rb +40 -0
- data/lib/clerq/interactors/interactor.rb +28 -0
- data/lib/clerq/interactors/join_nodes.rb +59 -0
- data/lib/clerq/interactors/query_nodes.rb +62 -0
- data/lib/clerq/properties.rb +21 -0
- data/lib/clerq/repositories.rb +5 -0
- data/lib/clerq/repositories/in_memory.rb +45 -0
- data/lib/clerq/repositories/node_reader.rb +107 -0
- data/lib/clerq/repositories/node_repository.rb +56 -0
- data/lib/clerq/repositories/repository.rb +11 -0
- data/lib/clerq/repositories/template_repository.rb +53 -0
- data/lib/clerq/settings.rb +56 -0
- data/lib/clerq/templater.rb +32 -0
- data/lib/clerq/version.rb +3 -0
- metadata +172 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
<%
|
2
|
+
# Template for drafts
|
3
|
+
require 'delegate'
|
4
|
+
class MarkupNode < SimpleDelegator
|
5
|
+
def title
|
6
|
+
'#' * nesting_level + ' ' + super
|
7
|
+
end
|
8
|
+
|
9
|
+
def meta
|
10
|
+
return '' if nesting_level == 0
|
11
|
+
return '' if super[:skip_meta]
|
12
|
+
|
13
|
+
hsh = {id: id}.merge(super)
|
14
|
+
hsh.delete(:order_index)
|
15
|
+
hsh.delete(:parent)
|
16
|
+
hsh.delete(:file_name)
|
17
|
+
[].tap{|ary|
|
18
|
+
ary << "Attribute | Value"
|
19
|
+
ary << "--------- | -----"
|
20
|
+
hsh.each{|k,v| ary << "#{k} | #{v}"}
|
21
|
+
}.join("\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def body
|
25
|
+
return '' if super.empty?
|
26
|
+
# replace links
|
27
|
+
txt = String.new(super)
|
28
|
+
links.each{|l| txt.gsub!("[[#{l}]]", link(l))}
|
29
|
+
txt
|
30
|
+
end
|
31
|
+
|
32
|
+
def link(id)
|
33
|
+
r = find_node(id)
|
34
|
+
return "[#{id}](#unknown)" unless r
|
35
|
+
"[#{r.title}](##{url(r.id)})"
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [String] id Node id, when it starts with
|
39
|
+
# '.' it finds for first descendant by #end_with?
|
40
|
+
# '*' it finds first note by #end_with? from root
|
41
|
+
# @return [Node] or nil when node not found
|
42
|
+
def find_node(id)
|
43
|
+
return find{|n| n.id.end_with? id[1..-1]} if id.start_with? '.'
|
44
|
+
return root.find{|n| n.id.end_with? id[1..-1]} if id.start_with? '*'
|
45
|
+
root.find{|n| n.id.eql? id}
|
46
|
+
end
|
47
|
+
|
48
|
+
def url(id)
|
49
|
+
id.downcase
|
50
|
+
.gsub(/[^A-Za-z0-9]{1,}/, '-')
|
51
|
+
.gsub(/^-/, '')
|
52
|
+
.gsub(/-$/, '')
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
-%>
|
57
|
+
% <%= @object.title %>
|
58
|
+
% generated by Clerq on <%= Time.now.strftime('%B %e, %Y at %H:%M') %>
|
59
|
+
|
60
|
+
<% for @node in @object.to_a.drop(1) -%>
|
61
|
+
<% n = MarkupNode.new(@node) -%>
|
62
|
+
<%= [n.title, n.meta, n.body].select{|t| !t.empty?}.join("\n\n") %>
|
63
|
+
|
64
|
+
<% end %>
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<%
|
2
|
+
require 'delegate'
|
3
|
+
# Template for generate documents by Pandoc
|
4
|
+
class MarkupNode < SimpleDelegator
|
5
|
+
def title
|
6
|
+
[].tap do |ary|
|
7
|
+
ary << '#' * (nesting_level + 1)
|
8
|
+
ary << '[' + id + ']' unless __getobj__.meta[:skip_meta]
|
9
|
+
ary << super
|
10
|
+
end.join(' ')
|
11
|
+
end
|
12
|
+
|
13
|
+
def meta
|
14
|
+
return '' if nesting_level == 0
|
15
|
+
return '' if super[:skip_meta]
|
16
|
+
|
17
|
+
hsh = {}.merge(super)
|
18
|
+
hsh.delete(:order_index)
|
19
|
+
hsh.delete(:file_name)
|
20
|
+
hsh.delete(:parent)
|
21
|
+
return '' if hsh.empty?
|
22
|
+
|
23
|
+
[].tap{|ary|
|
24
|
+
ary << "Attribute | Value"
|
25
|
+
ary << "--------- | -----"
|
26
|
+
hsh.each{|k,v| ary << "#{k} | #{v}"}
|
27
|
+
}.join("\n")
|
28
|
+
end
|
29
|
+
|
30
|
+
def body
|
31
|
+
# links replacement
|
32
|
+
txt = String.new(super)
|
33
|
+
links.each{|l| txt.gsub! "[[#{l}]]", link(l)}
|
34
|
+
# macro substitution
|
35
|
+
macro.each{|m| txt.gsub! m.regex, m.substitution}
|
36
|
+
txt
|
37
|
+
end
|
38
|
+
|
39
|
+
def link(ref)
|
40
|
+
node = root.find{|n| n.id == ref}
|
41
|
+
return "[#{ref}](#unknown)" unless node
|
42
|
+
"[#{node.title}](##{url(node.title)})"
|
43
|
+
end
|
44
|
+
|
45
|
+
def url(id)
|
46
|
+
id.downcase
|
47
|
+
.gsub(/[^A-Za-z0-9]{1,}/, '-')
|
48
|
+
.gsub(/^-/, '')
|
49
|
+
.gsub(/-$/, '')
|
50
|
+
end
|
51
|
+
|
52
|
+
class Macro
|
53
|
+
attr_reader :regex
|
54
|
+
def initialize(regex, &substitution)
|
55
|
+
@regex, @substitution = regex, substitution
|
56
|
+
end
|
57
|
+
|
58
|
+
def substitution
|
59
|
+
@substitution.call()
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def macro
|
64
|
+
[].tap do |ary|
|
65
|
+
ary << Macro.new(/{{@@skip[\s\S]*?}}/, &Proc.new{ '' })
|
66
|
+
ary << Macro.new("{{@@list}}", &Proc.new{list})
|
67
|
+
ary << Macro.new("{{@@tree}}", &Proc.new{tree})
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def tree
|
72
|
+
this_level = nesting_level + 1
|
73
|
+
to_a.drop(1).inject([]) do |ary, n|
|
74
|
+
lead_spaces = ' ' * (n.nesting_level - this_level)
|
75
|
+
ary << "#{lead_spaces}* [#{n.title}](##{url(n.id)})"
|
76
|
+
end.join("\n")
|
77
|
+
end
|
78
|
+
|
79
|
+
def list
|
80
|
+
items.inject([]) do |ary, n|
|
81
|
+
ary << "* [#{n.title}](##{url(n.id)})"
|
82
|
+
end.join("\n")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
-%>
|
86
|
+
% <%= @object.title %>
|
87
|
+
% generated by Clerq on <%= Time.now.strftime('%B %e, %Y at %H:%M') %>
|
88
|
+
|
89
|
+
<% for @node in @object.to_a.drop(1) -%>
|
90
|
+
<% n = MarkupNode.new(@node) -%>
|
91
|
+
<%= [n.title, n.meta, n.body].select{|t| !t.empty?}.join("\n\n") %>
|
92
|
+
|
93
|
+
<% end %>
|
@@ -0,0 +1,88 @@
|
|
1
|
+
<%
|
2
|
+
require 'delegate'
|
3
|
+
# Template for generate documents by Pandoc
|
4
|
+
class MarkupNode < SimpleDelegator
|
5
|
+
def title
|
6
|
+
"#{'#' * nesting_level} #{super} {##{url(id)}}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def meta
|
10
|
+
return '' if nesting_level == 0
|
11
|
+
return '' if super[:skip_meta]
|
12
|
+
|
13
|
+
hsh = {id: id}.merge(super)
|
14
|
+
hsh.delete(:order_index)
|
15
|
+
hsh.delete(:file_name)
|
16
|
+
hsh.delete(:parent)
|
17
|
+
[].tap{|ary|
|
18
|
+
ary << "Attribute | Value"
|
19
|
+
ary << "--------- | -----"
|
20
|
+
hsh.each{|k,v| ary << "#{k} | #{v}"}
|
21
|
+
}.join("\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def body
|
25
|
+
# links replacement
|
26
|
+
txt = String.new(super)
|
27
|
+
links.each{|l| txt.gsub! "[[#{l}]]", link(l)}
|
28
|
+
# macro substitution
|
29
|
+
macro.each{|m| txt.gsub! m.regex, m.substitution}
|
30
|
+
txt
|
31
|
+
end
|
32
|
+
|
33
|
+
def link(ref)
|
34
|
+
node = root.find{|n| n.id == ref}
|
35
|
+
return "[#{ref}](#unknown)" unless node
|
36
|
+
"[#{node.title}](##{url(ref)})"
|
37
|
+
end
|
38
|
+
|
39
|
+
def url(id)
|
40
|
+
id = 'p' + id if id[0] == '0'
|
41
|
+
id.downcase
|
42
|
+
.gsub(/[^A-Za-z0-9]{1,}/, '-')
|
43
|
+
.gsub(/^-/, '')
|
44
|
+
.gsub(/-$/, '')
|
45
|
+
end
|
46
|
+
|
47
|
+
class Macro
|
48
|
+
attr_reader :regex
|
49
|
+
def initialize(regex, &substitution)
|
50
|
+
@regex, @substitution = regex, substitution
|
51
|
+
end
|
52
|
+
|
53
|
+
def substitution
|
54
|
+
@substitution.call()
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def macro
|
59
|
+
[].tap do |ary|
|
60
|
+
ary << Macro.new(/{{@@skip[\s\S]*?}}/, &Proc.new{ '' })
|
61
|
+
ary << Macro.new("{{@@list}}", &Proc.new{list})
|
62
|
+
ary << Macro.new("{{@@tree}}", &Proc.new{tree})
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def tree
|
67
|
+
this_level = nesting_level + 1
|
68
|
+
to_a.drop(1).inject([]) do |ary, n|
|
69
|
+
lead_spaces = ' ' * (n.nesting_level - this_level)
|
70
|
+
ary << "#{lead_spaces}* [#{n.title}](##{url(n.id)})"
|
71
|
+
end.join("\n")
|
72
|
+
end
|
73
|
+
|
74
|
+
def list
|
75
|
+
items.inject([]) do |ary, n|
|
76
|
+
ary << "* [#{n.title}](##{url(n.id)})"
|
77
|
+
end.join("\n")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
-%>
|
81
|
+
% <%= @object.title %>
|
82
|
+
% generated by Clerq on <%= Time.now.strftime('%B %e, %Y at %H:%M') %> using 'pandoc.md.erb' template
|
83
|
+
|
84
|
+
<% for @node in @object.to_a.drop(1) -%>
|
85
|
+
<% n = MarkupNode.new(@node) -%>
|
86
|
+
<%= [n.title, n.meta, n.body].select{|t| !t.empty?}.join("\n\n") %>
|
87
|
+
|
88
|
+
<% end %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<%
|
2
|
+
# template for saving created nodes
|
3
|
+
require 'delegate'
|
4
|
+
class MarkupNode < SimpleDelegator
|
5
|
+
def title
|
6
|
+
'#' * (nesting_level + 1) + ' [' + id + '] ' + super
|
7
|
+
end
|
8
|
+
|
9
|
+
def meta
|
10
|
+
return '' if super.empty?
|
11
|
+
[].tap{|ary|
|
12
|
+
ary << '{{'
|
13
|
+
hsh.each{|k,v| ary << "#{k}: #{v}"}
|
14
|
+
ary << '}}'
|
15
|
+
}.join("\n")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
-%>
|
19
|
+
<% for @node in @object.to_a.drop(1) -%>
|
20
|
+
<% n = MarkupNode.new(@node) -%>
|
21
|
+
<%= [n.title, n.meta, n.body].select{|t| !t.empty?}.join("\n\n") %>
|
22
|
+
|
23
|
+
<% end %>
|
data/lib/clerq.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'clerq/version'
|
2
|
+
require_relative 'clerq/entities'
|
3
|
+
require_relative 'clerq/gateways'
|
4
|
+
require_relative 'clerq/interactors'
|
5
|
+
require_relative 'clerq/repositories'
|
6
|
+
require_relative 'clerq/properties'
|
7
|
+
require_relative 'clerq/settings'
|
8
|
+
require_relative 'clerq/templater'
|
9
|
+
require_relative 'clerq/cli'
|
10
|
+
|
11
|
+
module Clerq
|
12
|
+
class Error < StandardError; end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
def root
|
17
|
+
File.dirname __dir__
|
18
|
+
end
|
19
|
+
|
20
|
+
def gateway
|
21
|
+
@gateway ||= Clerq::Gateways::InFiles.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def gateway=(gateway)
|
25
|
+
errmsg = "Invalid argument! Clark::Gateway required"
|
26
|
+
raise ArgumentError, errmsg unless gateway.is_a? Clerq::Gateways::Gateway
|
27
|
+
@gateway = gateway
|
28
|
+
end
|
29
|
+
|
30
|
+
def settings
|
31
|
+
@settings ||= Settings.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset
|
35
|
+
@gateway = nil
|
36
|
+
@settings = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/lib/clerq/cli.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require_relative 'interactors'
|
5
|
+
include Clerq::Interactors
|
6
|
+
|
7
|
+
module Clerq
|
8
|
+
|
9
|
+
class Cli < Thor
|
10
|
+
include Thor::Actions
|
11
|
+
namespace :clerq
|
12
|
+
|
13
|
+
def self.source_root
|
14
|
+
File.join Clerq.root, "lib/assets"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "--version, -v", "Print the version"
|
18
|
+
def version
|
19
|
+
puts "Clerq v#{Clerq::VERSION}"
|
20
|
+
end
|
21
|
+
map %w[--version -v] => :version
|
22
|
+
|
23
|
+
desc "new PROJECT", "Create a new Clerq project"
|
24
|
+
def new(project)
|
25
|
+
say "Creating project '#{project}'..."
|
26
|
+
|
27
|
+
if Dir.exist?(project)
|
28
|
+
error "Directory '#{project}' already exists!"
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
settings = Clerq.settings
|
33
|
+
tts = [
|
34
|
+
{tt: 'new/README.md.tt', target: 'README.md'},
|
35
|
+
{tt: 'new/clerq.yml.tt', target: 'clerq.yml'},
|
36
|
+
{tt: 'new/clerq.thor.tt', target: "#{project}.thor"},
|
37
|
+
{tt: 'new/content.md.tt', target: File.join(settings.src, "#{project}.md")}
|
38
|
+
]
|
39
|
+
|
40
|
+
Dir.mkdir(project)
|
41
|
+
Dir.chdir(project) do
|
42
|
+
settings.folders.each{|f| Dir.mkdir(f)}
|
43
|
+
tts.each do |tt|
|
44
|
+
template(tt[:tt], File.join(Dir.pwd, tt[:target]), {project: project})
|
45
|
+
end
|
46
|
+
directory('tt', File.join(Dir.pwd, 'tt'))
|
47
|
+
say "Project created!"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "promo", "Copy content of promo project"
|
52
|
+
def promo
|
53
|
+
say "Copying promo content ..."
|
54
|
+
directory('promo', Dir.pwd)
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "build [OPTIONS]", "Build the clerq project"
|
58
|
+
method_option :query, aliases: "-q", type: :string, desc: "query"
|
59
|
+
method_option :tt, aliases: "-t", type: :string, desc: "template"
|
60
|
+
method_option :output, aliases: "-o", type: :string, desc: "output file"
|
61
|
+
def build
|
62
|
+
settings = Clerq.settings
|
63
|
+
document = options[:output] || settings.document + '.md'
|
64
|
+
template = options[:tt] || settings.template
|
65
|
+
query = options[:query] || ''
|
66
|
+
build = File.join(settings.bin, document)
|
67
|
+
content = CompileNodes.(template: template, query: query)
|
68
|
+
File.write(build, content)
|
69
|
+
say "'#{build}' created!"
|
70
|
+
rescue CompileNodes::Failure => e
|
71
|
+
error e.message
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "check", "Check the project for errors"
|
75
|
+
def check
|
76
|
+
errors = CheckNodes.()
|
77
|
+
if errors.empty?
|
78
|
+
say "No errors found"
|
79
|
+
return
|
80
|
+
end
|
81
|
+
|
82
|
+
CHECK_MESSAGES.each do |key, msg|
|
83
|
+
if errors.key?(key)
|
84
|
+
say "The following #{msg[0]}:"
|
85
|
+
errors[key].each{|k,v| say "\t#{k}\t#{msg[1]} #{v.join(', ')}"}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
rescue CheckNodes::Failure => e
|
89
|
+
error e.message
|
90
|
+
end
|
91
|
+
|
92
|
+
CHECK_MESSAGES = {
|
93
|
+
nonuniq_ids: ['node identifiers are non-uniqe', 'in'],
|
94
|
+
unknown_parents: ['meta[:parent] not found', 'in'],
|
95
|
+
unknown_references: ['links are unknown', 'in'],
|
96
|
+
unknown_order_index: ['node meta[:order_index] unknown', ':']
|
97
|
+
}.freeze
|
98
|
+
|
99
|
+
desc "node ID [TITLE]", "Create a new node"
|
100
|
+
method_option :template, aliases: "-t", type: :string, desc: "template"
|
101
|
+
def node(id, title = '')
|
102
|
+
settings = Clerq.settings
|
103
|
+
file = File.join(settings.src, "#{id}.md")
|
104
|
+
if File.exist?(file)
|
105
|
+
error "File already exists #{fn}"
|
106
|
+
return
|
107
|
+
end
|
108
|
+
template = options[:template] || ''
|
109
|
+
CreateNode.(id: id, title: title, template: template)
|
110
|
+
say "'#{file}' created"
|
111
|
+
rescue CreateNode::Failure => e
|
112
|
+
error e.message
|
113
|
+
end
|
114
|
+
|
115
|
+
desc "toc [OPTIONS]", "Print the project TOC"
|
116
|
+
method_option :query, aliases: "-q", type: :string, desc: "Query"
|
117
|
+
def toc
|
118
|
+
query = options[:query]
|
119
|
+
node = query ? QueryNodes.(query: query) : JoinNodes.()
|
120
|
+
puts "% #{node.title}"
|
121
|
+
node.to_a.drop(1).each{|n|
|
122
|
+
puts "#{' ' * (n.nesting_level - 1)}[#{n.id}] #{n.title}"
|
123
|
+
}
|
124
|
+
rescue QueryNodes::Failure, JoinNodes::Failure => e
|
125
|
+
error e.message
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|