From 5783c35b861efc9e3038241162a9bbf57b628fc0 Mon Sep 17 00:00:00 2001 From: Nikolay Voynov Date: Tue, 19 Nov 2019 00:51:45 +0200 Subject: [PATCH] improved creation new project with multi-word name --- CHANGELOG.md | 19 ++++++++++++ TODO.md | 14 ++++----- clerq.gemspec | 4 +-- lib/assets/new/clerq.thor.tt | 2 +- lib/clerq/cli.rb | 58 ++++++++++++++++++++++++++---------- lib/clerq/settings.rb | 4 +-- test/cli/cli_build_spec.rb | 8 +++++ test/cli/cli_check_spec.rb | 8 +++++ test/cli/cli_new_spec.rb | 2 +- test/cli/cli_node_spec.rb | 22 ++++++++++++++ test/cli/cli_toc_spec.rb | 10 ++++++- 11 files changed, 119 insertions(+), 32 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 test/cli/cli_node_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dad7245 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# Change log + +## master (unreleased) + +The main purpose of the gem was changed to more general text nodes repository management. The requirements management still my original reason, but it is achieved rather through adjustment than by basic features. That way was updated descriptions in `gemspec` and the repository. + +According to this big shift, I'm planning to record a few basic videos "How to write big documents with Clerq". At the moment I created the clerq project [Clerq Video Guide](https://github.com/nvoynov/clerq-video-guide) and the first script. You can just download this at [Clerq Video Guide.pdf](https://github.com/nvoynov/clerq-video-guide/blob/master/bin/Clerq Video Guide.pdf). I hope I'll have time to create an episode on how to meet requirements management challenges. + +Changes: + + * Improved `JoinNodes.call()`. When the result node contains the only single child item, it will return the child item orphaned. + * Improved `clerq new PROJECT` command. When the `PROJECT` parameter consists of more than one word, It will create `.thor` file that follows to usual ruby file and class naming conventions; e.g. for `user guide` it will create `user_guide.thor` and `class UserGuide < Thor` inside. + * Thor `error(msg)` in `cli.rb` changed to `stop!(mgs); raise Thor::Error`. + * Improved CLI for `build`, `check`, `toc`; now these check if the command run in clerq project, checked if `clerq.yml` or `src` folder exist. + * Added `cli_node_spec.rb` stub + +## 0.1.0 (2019-11-08) + +First release diff --git a/TODO.md b/TODO.md index 3e53ef1..2f1bfd3 100644 --- a/TODO.md +++ b/TODO.md @@ -1,13 +1,9 @@ % TODO -[ ] Handle `PROJECT` parameter of `clerq new PROJECT` for `.thor` when it consists of few words. -[ ] Remove comment at the top of `assets/clerq.thor` -[ ] Add CHANGELOG.md +[ ] Add `query` parameter to `JoinNodes.()` and remove `QueryNodes` interactor +[ ] Add spec to `clerq node` +[ ] Remove handling `skip_meta` from `default.md.erb` [ ] Release v0.2.0 -[ ] {{@@list(id)}} macro for other node like in overview section -[ ] Console like rails console -[ ] Fix descriptions in gemspec -[ ] `-s/--skip-clerq-assets` or `-a/--copy-assets` for `clerq new`? -[ ] Build README.md by Clerq! Wiki? -[ ] Record short video and upload to youtube [ ] Fix minitest "DEPRECATE" warning +[ ] Fix `bundle exec rake test` for errors in `cli_build_spec.rb` +[ ] Add macro with parameters like `{{@@list(id)}}` diff --git a/clerq.gemspec b/clerq.gemspec index bcfd1c1..028a6d8 100644 --- a/clerq.gemspec +++ b/clerq.gemspec @@ -9,8 +9,8 @@ Gem::Specification.new do |spec| spec.authors = ["Nikolay Voynov"] spec.email = ["nvoynov@gmail.com"] - spec.summary = %q{Toolkit for requirements management} - spec.description = %q{The gem provides requirements markup; file based requirements project structure; document templates; customizable CLI for managing requirements projects.} + spec.summary = %q{Text node repository and automation of managing large structured texts.} + spec.description = %q{The gem provides text nodes markup, text repository, advanced customizable CLI for managing repository, the powerful templating system for text transformation that perfect matches for managing large structured texts.} spec.homepage = "https://github.com/nvoynov/clerq" spec.license = "MIT" diff --git a/lib/assets/new/clerq.thor.tt b/lib/assets/new/clerq.thor.tt index d179906..e8a9e2c 100644 --- a/lib/assets/new/clerq.thor.tt +++ b/lib/assets/new/clerq.thor.tt @@ -1,7 +1,7 @@ require 'clerq' require 'thor' -class <%=config[:project].capitalize%> < Thor +class <%=config[:klass]%> < Thor include Thor::Actions desc "stat", "Print statistic" diff --git a/lib/clerq/cli.rb b/lib/clerq/cli.rb index 506293e..f920ec5 100644 --- a/lib/clerq/cli.rb +++ b/lib/clerq/cli.rb @@ -20,28 +20,52 @@ def version end map %w[--version -v] => :version + no_commands { + # @param [String] + # @returns [String] usual name for ruby file + def thor_file_name(str); + str.split(/[\W+_]/).map(&:downcase).join('_') + '.thor' + end + + # @param [String] + # @returns [String] usual name for ruby class + def ruby_class_name(str); + str.split(/[\W+_]/).map(&:capitalize).join + end + + def clerq_project? + File.exist?(Clerq::Settings::STORAGE) || Dir.exist?(Clerq.settings.src) + end + + def stop_unless_clerq! + stop! "Clerq project required!" unless clerq_project? + end + + def stop!(msg) + raise Thor::Error, msg + end + } + desc "new PROJECT", "Create a new Clerq project" def new(project) + stop! "'#{project}' folder already exists!" if Dir.exist?(project) say "Creating project '#{project}'..." - if Dir.exist?(project) - error "Directory '#{project}' already exists!" - return - end - settings = Clerq.settings tts = [ {tt: 'new/README.md.tt', target: 'README.md'}, - {tt: 'new/clerq.yml.tt', target: 'clerq.yml'}, - {tt: 'new/clerq.thor.tt', target: "#{project}.thor"}, + {tt: 'new/clerq.yml.tt', target: Clerq::Settings::STORAGE}, + {tt: 'new/clerq.thor.tt', target: thor_file_name(project)}, {tt: 'new/content.md.tt', target: File.join(settings.src, "#{project}.md")} ] + config = {project: project, klass: ruby_class_name(project)} + Dir.mkdir(project) Dir.chdir(project) do settings.folders.each{|f| Dir.mkdir(f)} tts.each do |tt| - template(tt[:tt], File.join(Dir.pwd, tt[:target]), {project: project}) + template(tt[:tt], File.join(Dir.pwd, tt[:target]), config) end directory('tt', File.join(Dir.pwd, 'tt')) say "Project created!" @@ -52,6 +76,7 @@ def new(project) def promo say "Copying promo content ..." directory('promo', Dir.pwd) + say "Copied!" end desc "build [OPTIONS]", "Build the clerq project" @@ -59,6 +84,7 @@ def promo method_option :tt, aliases: "-t", type: :string, desc: "template" method_option :output, aliases: "-o", type: :string, desc: "output file" def build + stop_unless_clerq! settings = Clerq.settings document = options[:output] || settings.document + '.md' template = options[:tt] || settings.template @@ -68,11 +94,12 @@ def build File.write(build, content) say "'#{build}' created!" rescue CompileNodes::Failure => e - error e.message + stop!(e.message) end desc "check", "Check the project for errors" def check + stop_unless_clerq! errors = CheckNodes.() if errors.empty? say "No errors found" @@ -86,7 +113,7 @@ def check end end rescue CheckNodes::Failure => e - error e.message + stop!(e.message) end CHECK_MESSAGES = { @@ -99,22 +126,21 @@ def check desc "node ID [TITLE]", "Create a new node" method_option :template, aliases: "-t", type: :string, desc: "template" def node(id, title = '') + stop_unless_clerq! settings = Clerq.settings file = File.join(settings.src, "#{id}.md") - if File.exist?(file) - error "File already exists #{fn}" - return - end + stop!("File already exists #{fn}") if File.exist?(file) template = options[:template] || '' CreateNode.(id: id, title: title, template: template) say "'#{file}' created" rescue CreateNode::Failure => e - error e.message + stop!(e.message) end desc "toc [OPTIONS]", "Print the project TOC" method_option :query, aliases: "-q", type: :string, desc: "Query" def toc + stop_unless_clerq! query = options[:query] node = query ? QueryNodes.(query: query) : JoinNodes.() puts "% #{node.title}" @@ -122,7 +148,7 @@ def toc puts "#{' ' * (n.nesting_level - 1)}[#{n.id}] #{n.title}" } rescue QueryNodes::Failure, JoinNodes::Failure => e - error e.message + stop!(e.message) end end diff --git a/lib/clerq/settings.rb b/lib/clerq/settings.rb index dfaa201..7a592f3 100644 --- a/lib/clerq/settings.rb +++ b/lib/clerq/settings.rb @@ -12,9 +12,9 @@ class Settings STORAGE = 'clerq.yml'.freeze # binary document settings that can be changed through 'clerq.yml' - property :document, default: 'Clеrk SRS' + property :document, default: 'Clеrq SRS' property :template, default: 'default.md.erb' - property :title, default: 'Clеrk SRS' + property :title, default: 'Clеrq SRS' # folders structure property :bin, default: 'bin' diff --git a/test/cli/cli_build_spec.rb b/test/cli/cli_build_spec.rb index bf00f2b..3d7b445 100644 --- a/test/cli/cli_build_spec.rb +++ b/test/cli/cli_build_spec.rb @@ -12,6 +12,14 @@ def prepare_repo File.write(File.join(settings.src, 'content.md'), content) end + describe 'when exec outside Clerq' do + it 'must stop' do + _(proc { Clerq::Cli.start ['build'] }).must_output( + "", /Clerq project required!/ + ) + end + end + describe 'when exec without options' do it 'must buid document by default' do diff --git a/test/cli/cli_check_spec.rb b/test/cli/cli_check_spec.rb index 817d1c6..1d43832 100644 --- a/test/cli/cli_check_spec.rb +++ b/test/cli/cli_check_spec.rb @@ -3,6 +3,14 @@ describe '#check' do let(:source) { File.join(Clerq.settings.src, 'contents.md') } + describe 'when exec outside Clerq' do + it 'must stop' do + _(proc { Clerq::Cli.start ['check'] }).must_output( + "", /Clerq project required!/ + ) + end + end + it 'must not raise exception at least' do Sandbox.project do Clerq::Cli.start ['check'] diff --git a/test/cli/cli_new_spec.rb b/test/cli/cli_new_spec.rb index 893c99d..e00dd67 100644 --- a/test/cli/cli_new_spec.rb +++ b/test/cli/cli_new_spec.rb @@ -32,7 +32,7 @@ Sandbox.() do FileUtils.rm_rf(Dir.glob('*')) Clerq::Cli.start args - _(proc { Clerq::Cli.start args }).must_output(/Creating/m, /already exists!/m) + _(proc { Clerq::Cli.start args }).must_output("", /already exists!/m) end end end diff --git a/test/cli/cli_node_spec.rb b/test/cli/cli_node_spec.rb new file mode 100644 index 0000000..188a31c --- /dev/null +++ b/test/cli/cli_node_spec.rb @@ -0,0 +1,22 @@ +require_relative '../spec_helper' + +describe 'clerq node' do + + describe 'when exec outside Clerq' do + it 'must stop' do + _(proc { Clerq::Cli.start ['build'] }).must_output( + "", /Clerq project required!/ + ) + end + end + + describe 'when exec with ID' do + end + + describe 'when exec with ID TITLE' do + end + + describe 'when exec with ID -t' do + end + +end diff --git a/test/cli/cli_toc_spec.rb b/test/cli/cli_toc_spec.rb index b1e09ad..2b6b217 100644 --- a/test/cli/cli_toc_spec.rb +++ b/test/cli/cli_toc_spec.rb @@ -32,6 +32,14 @@ EOF } + describe 'when exec outside Clerq' do + it 'must stop' do + _(proc { Clerq::Cli.start ['toc'] }).must_output( + "", /Clerq project required!/ + ) + end + end + it 'must return toc' do Sandbox.project do File.write(source, content) @@ -41,7 +49,7 @@ hsh[cmd3] = "% #{Clerq.settings.title}. Query: #{cmd3.last}\n" hsh.keys.each do |cmd| - _(proc {Clerq::Cli.start cmd}).must_output hsh[cmd] + _(proc {Clerq::Cli.start cmd}).must_output hsh[cmd], "" end end