Class: Courseware::Manager

Inherits:
Object
  • Object
show all
Defined in:
lib/courseware/manager.rb,
lib/courseware/manager/validators.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, repository = nil, generator = nil, printer = nil) ⇒ Manager

Returns a new instance of Manager.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/courseware/manager.rb', line 11

def initialize(config, repository=nil, generator=nil, printer=nil)
  @config     = config
  @repository = repository || Courseware::Repository.new(config)
  @generator  = generator  || Courseware::Generator.new(config)
  @warnings   = 0
  @errors     = 0

  return if @config[:presfile] == :none

  showoff     = Courseware.parse_showoff(@config[:presfile])
  @coursename = showoff['name']
  @prefix     = showoff['name'].gsub(' ', '_')
  @password   = showoff['key']
end

Instance Attribute Details

#coursenameObject (readonly)

Returns the value of attribute coursename.



9
10
11
# File 'lib/courseware/manager.rb', line 9

def coursename
  @coursename
end

#errorsObject (readonly)

Returns the value of attribute errors.



9
10
11
# File 'lib/courseware/manager.rb', line 9

def errors
  @errors
end

#prefixObject (readonly)

Returns the value of attribute prefix.



9
10
11
# File 'lib/courseware/manager.rb', line 9

def prefix
  @prefix
end

#warningsObject (readonly)

Returns the value of attribute warnings.



9
10
11
# File 'lib/courseware/manager.rb', line 9

def warnings
  @warnings
end

Instance Method Details

#lintObject



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/courseware/manager/validators.rb', line 94

def lint
  courselevel!

  puts "Checking Markdown style:"
  style  = File.join(@config[:cachedir], 'templates', 'markdown_style.rb')
  style  = File.exists?(style) ? style : 'all'
  issues = 0

  unless system('mdl', '--version')
    puts '  * Markdown linter not found: gem install mdl'
    puts
    @warnings += 1
    return
  end

  Dir.glob('**/*.md') do |file|
    next if File.symlink? file
    next if File.directory? file
    next if file =~ /^_.*$|^[^\/]*$/

    issues += 1 unless system('mdl', '-s', style, file)
  end

  if issues > 0
    puts
    puts 'Rule explanations can be found at:'
    puts '  * https://github.com/mivok/markdownlint/blob/master/docs/RULES.md'
    puts
    @warnings += issues
  end
end

#missingObject



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/courseware/manager/validators.rb', line 64

def missing
  courselevel!

  filename = @config[:presfile]
  content  = JSON.parse(`showoff info -jf #{filename}`)
  sections = content['files']
  images   = content['images']

  # This seems backwards, but we do it this way to get a case sensitive match on a case-insensitive-preserving filesystem
  # http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob -- Baby jesus is crying.
  Dir.glob("**{,/*/**}/*.md") do |file|
    sections.delete(file)
  end
  Dir.glob("_images/**{,/*/**}/*") do |file|
    images.delete(file)
  end

  puts "Missing slides:" unless sections.empty?
  sections.each do |slide|
    puts "  * #{slide}"
    @errors += 1
  end

  puts "Missing images:" unless images.empty?
  images.each do |slide|
    puts "  * #{slide}"
    @errors += 1
  end
end

#obsoleteObject



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/courseware/manager/validators.rb', line 3

def obsolete
  toplevel!

  allslides = Dir.glob('_content/**/*.md')
  allimages = Dir.glob('_images/**/*').reject {|path| path.include? '_images/src' }
  slides    = []
  images    = []

  Dir.glob('*').each do |path|
    next if path == 'spec'
    next if path.start_with? '_'
    next unless File.directory? path

    print "Validating #{path}."

    # stuff presentation local slides & images into the collections of available content
    allslides.concat Dir.glob("#{path}/**/*.md").reject {|file| file.include?('README.md')      ||
                                                                file.include?('_notes')         ||
                                                                File.dirname(file) == path }

    allimages.concat Dir.glob("#{path}/_images/**/*").reject {|file| file.include?('README.md') ||
                                                                     file.include?('src/')      ||
                                                                     File.directory?(file) }

    Dir.chdir(path) do
      Dir.glob('*.json').each do |filename|
        # determine which slides and images are actually used
        content = JSON.parse(`showoff info -jf #{filename}`)
        lslides = content['files'].map do |slide|
          slide.start_with?('_') ? slide.sub('_shared', '_content') : "#{path}/#{slide}"
        end
        limages = content['images'].map do |image|
          image.start_with?('_images/shared') ? image.sub('_images/shared', '_images') : "#{path}/#{image}"
        end

        slides.concat(lslides)
        images.concat(limages)

        print '.'
      end
      puts
    end
  end

  # remove the intersection, and what's left over is obsolete
  obs_slides = (allslides - slides.uniq!)
  obs_images = (allimages - images.uniq!)

  puts "Obsolete slides:" unless obs_slides.empty?
  obs_slides.each do |slide|
    puts "  * #{slide}"
    @warnings += 1
  end

  puts "Obsolete images:" unless obs_images.empty?
  obs_images.each do |image|
    puts "  * #{image}"
    @warnings += 1
  end
end

#release(type) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/courseware/manager.rb', line 50

def release(type)
  courselevel!
  master!
  clean!

  @repository.update
  version = Courseware.increment(@repository.current(@coursename), type)
  Courseware.bailout?("Building a release for #{@coursename} version #{version}.")

  raise "Release notes not updated for #{version}" if Dir.glob('Release-Notes*').select { |path| Courseware.grep(version, path) }.empty?

  Courseware.dialog('Last Repository Commit', @repository.last_commit)
  Courseware.bailout?('Abort now if the commit message displayed is not what you expected.')
  build_pdfs(version)
  point_of_no_return
  Courseware.bailout?('Please inspect the generated PDF files and abort if corrections must be made.', true) do
    @repository.discard(@config[:stylesheet])
  end

  @repository.commit(@config[:stylesheet], "Updating for #{@coursename} release #{version}")
  @repository.tag("#{@prefix}-#{version}", "Releasing #{@coursename} version #{version}")

  # places the PDF files should be uploaded to
  @config[:release][:links].each do |link|
    system("open #{link}")
  end

  puts "Release shipped. Please upload PDF files to printer and break out the bubbly."
end

#releasenotesObject



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/courseware/manager.rb', line 26

def releasenotes
  courselevel!
  master!
  clean!

  @repository.update
  current = @repository.current(@coursename)
  version = Courseware.increment(current)
  tag     = "#{@coursename}-#{current}"

  notes = @repository.releasenotes(tag, version)

  # print to screen
  puts notes

  # and copy if on OS X
  begin
    IO.popen('pbcopy', 'w') { |f| f.puts notes }
    puts
    puts "{{ Copied to clipboard }}"
  rescue
  end
end

#wordcount(subject) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/courseware/manager.rb', line 80

def wordcount(subject)
  $logger.debug "Counting words for #{subject}"
  opts = print_opts(@repository.current(prefix))
  puts "Words longer than a single character:"
  Courseware::Printer.new(@config, opts) do |printer|
    subject.each do |item|
      printer.generate_html(item)
      doc   = Nokogiri::HTML(File.read('static/index.html'))
      count = doc.css('body').text.split.select {|w| w.size > 1 }.count

      puts "  * #{item}: #{count}"

      FileUtils.rm_rf('static')
    end
  end
end