class Creq::Repository

Public Class Methods

call(repo = read_repo) click to toggle source
# File lib/creq/repository.rb, line 18
def self.call(repo = read_repo)
  r = new
  r.load(repo)
  r
end
new() click to toggle source
Calls superclass method
# File lib/creq/repository.rb, line 36
def initialize
  super({id: 'root'})
  @reqfs = {} # requirements file map {req_id, [file_name]}
end
read_repo(repository = '**/*.md') click to toggle source
# File lib/creq/repository.rb, line 24
def self.read_repo(repository = '**/*.md')
  {}.tap do |repo|
    Dir.glob(repository) do |f|
      print "Read file '#{f}' ... "
      reqs = nil
      output = capture_stdout { reqs = Reader.(f) }
      puts output.empty? ? "OK!" : "with errors\n#{output}"
      repo[f] = reqs
    end
  end
end

Public Instance Methods

duplicate_ids() click to toggle source
# File lib/creq/repository.rb, line 152
def duplicate_ids
  dup = []
  inject([], :<<)
    .tap{|r| r.delete_at(0)}
    .map(&:id)
    .tap{|r| dup = r.select{|id| r.count(id) > 1}.uniq}

  dup.inject([]) do |err, id|
    err << "[#{id}] in #{@reqfs[id].join(', ')}"
  end
end
generate_missing_ids() click to toggle source
# File lib/creq/repository.rb, line 90
def generate_missing_ids
  # if some requirements have no id they must be generated XX, XX.YY, XX.YY.ZZZ
  counter = {}
  select{|r| r.id.nil?}.each do |r|
    index = counter[r.parent_id] || 1
    counter[r.parent_id] = index + 1
    id = index.to_s.rjust(2, "0")
    id = '.' + id if r.parent
    r.id = id
  end
end
load(repo) click to toggle source
# File lib/creq/repository.rb, line 79
def load(repo)
  repo.each do |file, req|
    req.items.each{|r| self << r}
    flat = req.inject([], :<<).tap{|r| r.delete_at(0)}.flatten
    store_files(flat, file)
  end
  subordinate!
  expand_links!
  generate_missing_ids
end
query(query_str) click to toggle source

The method selects requirements matched to the query parameter. It evaluates `query_str` parameter as a Ruby proc with the input

parameter `r` that represents Creq:Requirements class

Examples of valid queries:

r.id == 'req.id'
['r1', 'r2'].include?(r.id)
['r1', 'r2'].include?(r.id) && r[:author] == 'john doe'

@param [String] query String @return [Array<TreeNode>] query result

# File lib/creq/repository.rb, line 53
def query(query_str)
  block = Proc.new {|r| eval(query_str)}    
  [].tap{|a|
    select{|n| block.call(n)}
     .each{|n| n.inject(a, :<<)}
  }.flatten.uniq

  # TODO how to delete some reqs?
  # res = select{|n| bck.call(n) }
  # del = select{|n| !bck.call(n)}
        # .inject([]){|ary, n| ary << n.inject([], :<<)}
        # .flatten
        # .uniq
  # puts "res: #{res.map(&:id)}"
  # puts "del: #{del.map(&:id)}"
  # puts "===: #{res.select{|n| !del.include?(n)}.map(&:id)}"
  # res.select{|n| !del.include?(n)}
rescue Exception => e
  puts "query error: #{e.message}"
  puts "valid query examples are:"
  puts "   r.id == 'req.id'"
  puts "   ['r1', 'r2'].include?(r.id)"
  puts "   ['r1', 'r2'].include?(r.id) && r[:author] == 'john doe'"
  return []
end
repo_identifiers() click to toggle source

@return Array<String> unique array of requirements identifiers

# File lib/creq/repository.rb, line 188
def repo_identifiers
  @identifiers ||= map(&:id).tap{|i| i.delete_at(0)}.uniq
  @identifiers
end
repo_requirements() click to toggle source

@return Array array of requirements

# File lib/creq/repository.rb, line 183
def repo_requirements
  inject([], :<<)
end
store_files(reqary, file) click to toggle source
# File lib/creq/repository.rb, line 146
def store_files(reqary, file)
  reqary.map(&:id).each{|id|
    @reqfs[id]? @reqfs[id] << file : @reqfs[id] = [file]
  }
end
subordinate!() click to toggle source
# File lib/creq/repository.rb, line 102
def subordinate!
  # clear parent for root.items, BUT WHY?
  @items.each{|r| r.parent = nil}

  @items.select{|r| r[:parent] && r.parent.nil?}.each{|r|
    parent = find(r[:parent])
    next unless parent # TODO or show a error?
    parent << r
    @items.delete(r)
  }
end
wrong_order_index() click to toggle source

TODO separated Checker class?

# File lib/creq/repository.rb, line 203
def wrong_order_index
  msg = "[%s] for [%s]"
  err = []
  @items.select{|r| r[:order_index] }.each do |r|
    childs = r[:order_index].split(/ /)
    wrongs = childs.select{|c| r.item(c).nil? }
    err << msg % [wrongs.join(', '), r.id] unless wrongs.empty?
  end
  err
end
wrong_parents() click to toggle source
# File lib/creq/repository.rb, line 193
def wrong_parents
  reqs = inject([], :<<).tap{|r| r.delete_at(0)}
      .select{|r| r[:parent] && r.parent.nil?}

  reqs.inject([]) do |err, r|
    err << "[#{r[:parent]}] for [#{r.id}] in #{@reqfs[r.id].join(', ')}"
  end
end