Guest User

Untitled

a guest
Feb 20th, 2018
268
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.47 KB | None | 0 0
  1. #!/bin/env ruby
  2. ###########################################################################
  3. # mkdwc: Behaves like wc(1) but operates on the raw text of one or more
  4. # Markdown or Textile files.
  5. # Tammy Cravit, tammy@tammycravit.us
  6. ###########################################################################
  7. # This code can also be included into another script if you want to extend
  8. # the MarkdownWC class.
  9. ###########################################################################
  10. # This is the third take on this script, and abstracts out the markup-
  11. # specific stuff as much as I know how to do. That way, the script can
  12. # fairly easily be expanded to support just about any markup that can be
  13. # easily converted to HTML, just by plugging in whatever code is needed
  14. # to render the markup, and writing a new formatter.
  15. ###########################################################################
  16.  
  17. # Include the gems and packages we need
  18. %w[rubygems peg_markdown RedCloth stringray optparse on_execute].each {
  19. |dep|
  20. require dep
  21. }
  22.  
  23. OPTIONS = {
  24. :chars => false,
  25. :words => false,
  26. :lines => false,
  27. :ingore_underscores => true,
  28. }
  29.  
  30. ###########################################################################
  31. # Load the StringRay stuff
  32. ###########################################################################
  33.  
  34. String.send :include, StringRay
  35.  
  36. ###########################################################################
  37. # These classes abstract out the markup-specific formatting stuff
  38. # so we can use one utility script for multiple markup languages.
  39. #
  40. # To create a new markup formatter engine, do the following:
  41. #
  42. # 1. Define a class that inherits from MarkupEngineFormatter
  43. # 2. Add a markup_engine method that returns the class name of the
  44. # markup processor. The markup processor must take the marked-up
  45. # text as an argument to initialize, and must define a to_html
  46. # method which returns valid HTML.
  47. # 3. Add a file_masks method that returns an array of the file extensions
  48. # which are valid for the new markup language.
  49. # 4. Add a file_type method that returns the name of the markup language.
  50. # This is used by optparse in displaying the usage message.
  51. # 5. Add a test to the on_execute block at the end of the script, which
  52. # dispatches to your new class based on the script name.
  53. # 6. Create a symlink from markupwc to the new script name you defined in
  54. # step 5.
  55. ###########################################################################
  56.  
  57. class MarkupEngineFormatter
  58. def initialize
  59. @file_content = ""
  60. end
  61.  
  62. def set_content(content)
  63. @file_content = content
  64. end
  65.  
  66. def strip(s)
  67. s.gsub(/<\/?[^>]*>/, "").gsub(/\&\#[0123456789]+\;/, "?")
  68. end
  69.  
  70. def strip_markup
  71. engine = markup_engine.new(@file_content)
  72. strip engine.to_html
  73. end
  74.  
  75. def select_files(alist)
  76. filemask = file_masks.join("|")
  77. alist.find_all{|item| item =~ /\.(#{filemask})$/}
  78. end
  79. end
  80.  
  81. # Formatter for Markdown files
  82. class MarkdownFormatter < MarkupEngineFormatter
  83. def markup_engine
  84. PEGMarkdown
  85. end
  86.  
  87. def file_masks
  88. %w[markdown mkd mdown markdn md]
  89. end
  90.  
  91. def file_type
  92. "Markdown"
  93. end
  94. end
  95.  
  96. # Formatter for Textile files
  97. class TextileFormatter < MarkupEngineFormatter
  98. def markup_engine
  99. RedCloth
  100. end
  101.  
  102. def file_masks
  103. %w[textile]
  104. end
  105.  
  106. def file_type
  107. "Textile"
  108. end
  109. end
  110.  
  111. ###########################################################################
  112. # MarkupWC is the main class for the application.
  113. ###########################################################################
  114.  
  115. class MarkupWC
  116.  
  117. def initialize(formatter,filetype)
  118. @formatter = formatter
  119. @filetype = @formatter.file_type
  120. end
  121.  
  122. # Count the characters, words and lines in a single Markdown file.
  123. def count_file(filepath)
  124. if File.exists?(filepath)
  125. file_lines = IO.readlines(filepath)
  126. lines = file_lines.count
  127. @formatter.set_content(file_lines.join("\n"))
  128. stripped = @formatter.strip_markup
  129. characters = stripped.length
  130. words = stripped.to_stray.select {
  131. |w| w.is_a? StringRay::Word }.size
  132. [characters,words,lines]
  133. else
  134. [0,0,0]
  135. end
  136. end
  137.  
  138. # Invoke count_file on a group of files, and display individual and
  139. # aggregate results
  140. def count_many_files(filelist)
  141. tchars = twords = tlines = 0
  142.  
  143. unless filelist.empty?
  144. filelist.each { |f|
  145. chars, words, lines = count_file(f)
  146. print_result f, chars, words, lines
  147. tchars += chars ; twords += words ; tlines += lines
  148. }
  149. if filelist.count > 1
  150. print_result "total", tchars, twords, tlines
  151. end
  152. end
  153. end
  154.  
  155. # Parse the command line options
  156. def parse_command_line
  157. o = OptionParser.new do |o|
  158. script_name = $0.split('/').last
  159.  
  160. o.set_summary_indent(' ')
  161.  
  162. o.banner = "Usage: #{script_name} [ -c | -w | -l ] <file> [file] ..."
  163. o.define_head "Count words, lines, and characters in one or more #{@filetype} files."
  164. o.separator ""
  165.  
  166. o.on("-c", "--chars", "Count only characters") { |OPTIONS[:chars]| }
  167. o.on("-w", "--words", "Count only words") { |OPTIONS[:words]| }
  168. o.on("-l", "--lines", "Count only lines") { |OPTIONS[:lines]| }
  169. o.on("-a", "--all-files",
  170. "Include files beginning with _") { |OPTIONS[:ignore_underscores]|}
  171. o.separator ""
  172.  
  173. o.on_tail("-h", "--help", "Show this help message") { puts o; exit }
  174. o.parse!(ARGV)
  175.  
  176. if ARGV.count == 0
  177. puts o
  178. exit
  179. end
  180.  
  181. numopts = 0
  182. %w[chars words lines].each { |opt| numopts += 1 if OPTIONS[opt.intern] }
  183. if numopts > 1
  184. puts "The -c, -w and -l options are mututally exclusive"
  185. puts ""
  186. puts o
  187. exit
  188. end
  189. end
  190. end
  191.  
  192. # Process a group of files specified on the command line. This is the
  193. # entrypoint for the script when it's invoked interactively.
  194. def process_files
  195. parse_command_line
  196.  
  197. filelist = @formatter.select_files(ARGV)
  198. unless OPTIONS[:ignore_underscores]
  199. filelist = filelist.find_all{|item| item !~ /^_/}
  200. end
  201. if filelist.empty?
  202. puts "#{$0.split('/').last}: filelist is empty"
  203. exit
  204. end
  205. count_many_files filelist
  206. end
  207.  
  208. private
  209. # Display the results for a single file.
  210. def print_result(file, chars, words, lines)
  211. if OPTIONS[:chars]
  212. printf "%6d %s\n", chars, file
  213. elsif OPTIONS[:words]
  214. printf "%6d %s\n", words, file
  215. elsif OPTIONS[:lines]
  216. printf "%6d %s\n", lines, file
  217. else
  218. printf "%6d %6d %6d %s\n", lines, words, chars, file
  219. end
  220. end
  221. end
  222.  
  223. ###########################################################################
  224. # Actually run the script from the command line
  225. ###########################################################################
  226.  
  227. on_execute do
  228. script_name = $0.split('/').last
  229. formatter, filetype = nil, ""
  230.  
  231. if script_name == "mkdwc" or script_name == "mmwc"
  232. formatter, filetype = MarkdownFormatter.new, "Markdown"
  233. elsif script_name == "ttwc"
  234. formatter, filetype = TextileFormatter.new, "Textile"
  235. else
  236. puts "Don't know what to do for script: #{$0}"
  237. exit
  238. end
  239.  
  240. unless formatter.nil?
  241. MarkupWC.new(formatter, filetype).process_files
  242. end
  243. end
Add Comment
Please, Sign In to add comment