murdoc 0.1.13 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ff69e5073e356e1352ca86544832cf54a4aa59fd
4
- data.tar.gz: 157c3522d529acf574fb7bca9c673dc5fde93d23
3
+ metadata.gz: 6ef249b35659b0df1ac35d233d7ded20dc29e45b
4
+ data.tar.gz: 7017b589cae5baf9511e1aaf065931b32d30c75a
5
5
  SHA512:
6
- metadata.gz: d48ee92831d38fb6299f1c1ba6fffc56579a4b0b99e8235d9813c50daec1146b9d2d1c0eca56222f69280ffe90c2eb8b7320c67ebec150619ff26036dd84f837
7
- data.tar.gz: 403188b4870aa15f253dd6222f9f5e49e8751965b15d2e1a7b11836d8d165be191103fdd2b655d7290741e6a560ef340a1f8ff6958d45bd83f4cd0bb8f86fc95
6
+ metadata.gz: 935006a39b60ce7b2d6c2d1c4eb8247758f36a60a2ce2174757d8befea55231dc5916b3c167d8d1c26b1f693c7eff06b0a7c7c4ca0f2713c12791b0b9d102e15
7
+ data.tar.gz: 87622f60399b0217f751cfa09b60eeea353d2af8a00727293057feaffac8de8ebc25ad3a7a5f5a16c186e57466214cb725911abde2fddaf922697ae7682a6227
@@ -0,0 +1,16 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+ Gemfile.lock
14
+
15
+ # jeweler generated
16
+ pkg
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --colour
2
+ --format d
@@ -1,6 +1,4 @@
1
1
  script: "bundle exec rake"
2
2
  rvm:
3
- - 1.8.7
4
- - 1.9.2
5
- - ree
3
+ - 2.1.5
6
4
  - jruby
data/Gemfile CHANGED
@@ -1,12 +1,3 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem "kramdown"
4
- gem "haml", "~> 3.0.0"
5
-
6
- group :development do
7
- gem "jeweler"
8
- gem "rake"
9
- gem "rspec", "~> 2.4.0"
10
- gem "rdiscount", "~> 1.6.5", :platform => :mri
11
- end
12
-
3
+ gemspec
data/README.md CHANGED
@@ -9,13 +9,13 @@ You may also want to see:
9
9
  * [Rocco](http://rtomayko.github.com/rocco/)
10
10
 
11
11
  Dependencies
12
- ============
12
+ ------------
13
13
 
14
14
  * Haml
15
15
  * Either RDiscount (for MRI rubies) or Kramdown (for non-mri rubies)
16
16
 
17
17
  Example
18
- =======
18
+ -------
19
19
 
20
20
  See example at [GH.pages](http://jsus.github.com/murdoc).
21
21
 
@@ -23,7 +23,7 @@ See also:
23
23
  * [example](http://jsus.github.com/murdoc/docs) of integration with [jsus](http://github.com/jsus/jsus)
24
24
  * [LSD documentation guides](https://github.com/lovelyscalabledrawings/lsd-guides/tree/gh-pages/grid)
25
25
 
26
- License and authorship
27
- ======================
26
+ License
27
+ -------
28
28
 
29
29
  Public domain, see UNLICENSE file.
data/Rakefile CHANGED
@@ -1,27 +1,5 @@
1
1
  require 'rubygems'
2
- require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
- require 'rake'
11
-
12
- require 'jeweler'
13
- Jeweler::Tasks.new do |gem|
14
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
- gem.name = "murdoc"
16
- gem.homepage = "http://github.com/markiz/murdoc"
17
- gem.license = "Public Domain"
18
- gem.summary = "Annotated documentation generator"
19
- gem.description = "Annotated documentation generator, see README.md for details"
20
- gem.email = "markizko@gmail.com"
21
- gem.authors = ["Mark Abramov"]
22
- gem.executables = ["murdoc", "murdoc-strip-comments"]
23
- end
24
- Jeweler::RubygemsDotOrgTasks.new
2
+ require "bundler/gem_tasks"
25
3
 
26
4
  require 'rspec/core'
27
5
  require 'rspec/core/rake_task'
data/bin/murdoc CHANGED
@@ -9,7 +9,7 @@ option_parser = OptionParser.new do |opts|
9
9
  opts.banner = "murdoc <input file> <output html>"
10
10
 
11
11
  opts.on("--[no-]syntax-highlight", "Highlight syntax using pygments") do |h|
12
- options[:highlight_source] = h
12
+ options[:highlight] = h
13
13
  end
14
14
 
15
15
  opts.on("-t", "--template [FILENAME]", "Use custom haml template for output") do |t|
@@ -2,9 +2,11 @@
2
2
  require "optparse"
3
3
  $: << "./lib/"
4
4
  require "murdoc"
5
+ require 'pp'
5
6
 
6
7
  options = {}
7
8
  source_type = nil
9
+ do_not_count_comment_lines = false
8
10
 
9
11
  option_parser = OptionParser.new do |opts|
10
12
  opts.banner = "murdoc-strip-comments [input file]\n\nWhen no input file is provided, murdoc-strip-comments uses standard input stream."
@@ -13,16 +15,27 @@ option_parser = OptionParser.new do |opts|
13
15
  source_type = st
14
16
  end
15
17
 
18
+ opts.on("--do-not-count-comment-lines") do |dncl|
19
+ do_not_count_comment_lines = dncl
20
+ end
21
+
16
22
  opts.on_tail("-h", "--help", "Show this message") do
17
23
  puts opts
18
24
  exit
19
25
  end
20
-
21
26
  end
22
27
 
23
28
  option_parser.parse!
24
29
 
25
- annotator = Murdoc::Annotator.from_file(ARGV[0] || "/dev/stdin", source_type, {})
30
+ annotator = Murdoc::Annotator.from_file(ARGV[0] || "/dev/stdin", source_type, do_not_count_comment_lines)
31
+ prev_paragraph = nil
26
32
  annotator.paragraphs.each do |paragraph|
27
- puts paragraph.source
33
+ if prev_paragraph
34
+ print "\n" * [(paragraph.starting_line - prev_paragraph.starting_line - prev_paragraph.source.lines.count), 0].max
35
+ end
36
+
37
+ if !(paragraph.source =~ /\A\s*\z/m)
38
+ puts paragraph.source
39
+ end
40
+ prev_paragraph = paragraph
28
41
  end
@@ -10,36 +10,50 @@
10
10
 
11
11
 
12
12
  module Murdoc
13
+ AnnotatedFile = Struct.new(:filename, :source, :source_type, :paragraphs, :formatted_paragraphs)
14
+
15
+ def self.annotate(filename, highlight = true, do_not_count_comment_lines = false)
16
+ filename = File.expand_path(filename)
17
+ annotator = Annotator.from_file(filename, nil, do_not_count_comment_lines)
18
+ AnnotatedFile.new(filename,
19
+ annotator.source,
20
+ annotator.source_type,
21
+ annotator.paragraphs,
22
+ annotator.paragraphs.map {|p| FormattedParagraph.new(p, highlight) })
23
+ end
24
+
13
25
  def self.generate_from_file(input, output, options = {})
14
26
  options = default_options.merge(options)
15
- annotator = Annotator.from_file(input, nil, options)
27
+ annotator = Annotator.from_file(input, nil)
16
28
  File.open(output, "w+") do |f|
17
- f.puts Formatter.new(options[:template]).render(:paragraphs => annotator.paragraphs,
18
- :stylesheet => File.read(options[:stylesheet]))
29
+ annotated_file = annotate(input, options[:highlight], options[:do_not_count_comment_lines])
30
+ f.puts Renderer.new(options[:template]).render(:annotated_file => annotated_file,
31
+ :stylesheet => File.read(options[:stylesheet]))
19
32
  end
20
33
  end
21
34
 
22
35
  def self.generate_from_multiple_files(input_files, output, options = {})
23
36
  options = default_options_for_multiple_files.merge(options)
24
- annotators = input_files.map {|fn| Annotator.from_file(fn, nil, options) }
37
+ annotated_files = input_files.map {|fn| annotate(fn, options[:highlight], options[:do_not_count_comment_lines]) }
25
38
  File.open(output, "w+") do |f|
26
- f.puts Formatter.new(options[:template]).render(:annotators => annotators,
27
- :filenames => input_files,
28
- :stylesheet => File.read(options[:stylesheet]))
39
+ f.puts Renderer.new(options[:template]).render(:annotated_files => annotated_files,
40
+ :stylesheet => File.read(options[:stylesheet]))
29
41
  end
30
42
  end
31
43
 
32
44
  def self.default_options
33
- @@options ||= {
34
- :template => "#{markup_dir}/template.haml",
35
- :stylesheet => "#{markup_dir}/stylesheet.css"
45
+ @options ||= {
46
+ template: "#{markup_dir}/template.haml",
47
+ stylesheet: "#{markup_dir}/stylesheet.css",
48
+ highlight: true
36
49
  }
37
50
  end
38
51
 
39
52
  def self.default_options_for_multiple_files
40
- @@options ||= {
41
- :template => "#{markup_dir}/template_multifile.haml",
42
- :stylesheet => "#{markup_dir}/stylesheet.css"
53
+ @options ||= {
54
+ template: "#{markup_dir}/template_multifile.haml",
55
+ stylesheet: "#{markup_dir}/stylesheet.css",
56
+ highlight: true
43
57
  }
44
58
  end
45
59
 
@@ -49,7 +63,13 @@ module Murdoc
49
63
  end
50
64
 
51
65
  require "murdoc/annotator"
66
+ require "murdoc/scanner"
52
67
  require "murdoc/paragraph"
53
- require "murdoc/formatter"
54
-
55
- Dir["#{File.dirname(File.expand_path(__FILE__))}/murdoc/languages/*.rb"].each {|lang| require lang }
68
+ require "murdoc/formatted_paragraph"
69
+ require "murdoc/renderer"
70
+ require "murdoc/languages/base"
71
+ require "murdoc/languages/html"
72
+ require "murdoc/languages/coffeescript"
73
+ require "murdoc/languages/javascript"
74
+ require "murdoc/languages/ruby"
75
+ require "murdoc/languages/markdown"
@@ -1,40 +1,33 @@
1
- # Annotator class does all the main job: parses out comments
2
- # and returns annotated code
3
-
4
-
5
- # Main module
6
1
  module Murdoc
7
2
  class Annotator
3
+ attr_accessor :source
4
+
8
5
  # Attribute accessor containing the resulting paragraphs
9
6
  attr_accessor :paragraphs
10
7
 
11
- # Options
12
- # Available options:
13
- # `:highlight_source` -- highlights source syntax using pygments (default: true)
14
- attr_accessor :options
15
-
16
- def self.default_options
17
- {
18
- :highlight_source => true
19
- }
20
- end
21
-
8
+ # Source language
9
+ attr_accessor :language
22
10
 
23
11
  # `source` string contains annotated source code
24
12
  # `source_type` is one of supported source types (currently `[:ruby, :javascript]`)
25
- def initialize(source, source_type, options = {})
13
+ def initialize(source, source_type, do_not_count_comment_lines = false)
26
14
  self.source_type = source_type
27
- self.options = self.class.default_options.merge(options)
15
+ self.language = Languages.get(source_type)
28
16
  self.source = source
17
+ self.paragraphs = if !language.annotation_only?
18
+ Scanner.new(language).call(source, do_not_count_comment_lines)
19
+ else
20
+ [Paragraph.new('', source, 0, nil)]
21
+ end
29
22
  end
30
23
 
31
24
 
32
25
  # You may also initialize annotator from file, it will even try to detect the
33
26
  # source type from extension.
34
- def self.from_file(filename, source_type = nil, options = {})
27
+ def self.from_file(filename, source_type = nil, do_not_count_comment_lines = false)
35
28
  self.new(File.read(filename),
36
- source_type || detect_source_type_from_filename(filename),
37
- options)
29
+ source_type || Languages.detect(filename),
30
+ do_not_count_comment_lines)
38
31
  end
39
32
 
40
33
  def source_type
@@ -42,122 +35,7 @@ module Murdoc
42
35
  end
43
36
 
44
37
  def source_type=(source_type)
45
- @source_type = source_type.to_s
46
- end
47
-
48
- # Big and hairy code parser
49
- def source=(src)
50
- @source = src
51
- @paragraphs = []
52
- lines = src.split("\n")
53
-
54
- # splitting stuff into lines and setting cursor into initial position
55
- i = 0
56
- source_lines_counter = 0
57
- while i < lines.size
58
- comment_lines = []
59
- # get single line comments
60
- if comment_symbols[:single_line]
61
- while i < lines.size && lines[i] =~ /^\s*#{Regexp.escape(comment_symbols[:single_line])}(.*)/
62
- comment_lines << $1
63
- i += 1
64
- end
65
- end
66
-
67
- # getting multiline comments
68
- if comment_symbols[:multiline]
69
- begin_symbol = Regexp.escape(comment_symbols[:multiline][:begin])
70
- end_symbol = Regexp.escape(comment_symbols[:multiline][:end])
71
- if i < lines.size && lines[i] =~ /\s*#{begin_symbol}/
72
- begin
73
- match = lines[i].match /\s*(#{begin_symbol})?\s?(.*?)(#{end_symbol}|$)/
74
- comment_lines << match[2]
75
- i += 1
76
- end while i < lines.size && !(lines[i-1] =~ /\s*#{end_symbol}/)
77
- end
78
- end
79
-
80
- # getting source lines
81
- source_lines = []
82
- starting_line = if options[:do_not_count_comment_lines]
83
- source_lines_counter
84
- else
85
- i
86
- end
87
-
88
- while i < lines.size && !is_comment(lines[i])
89
- source_lines << lines[i]
90
- source_lines_counter += 1
91
- i += 1
92
- end
93
-
94
- # post-processing: stripping comments and removing empty strings from beginnings and ends
95
- starting_line += postprocess_source(source_lines)
96
- postprocess_comments(comment_lines)
97
- # clear comment lines if that's commented out code
98
- comment_lines.clear if comment_lines[0] =~ /^:code:$/
99
-
100
- # if we have comments or source
101
- if comment_lines.size > 0 || source_lines.size > 0
102
- @paragraphs << Paragraph.new(source_lines.join("\n"),
103
- comment_lines.join("\n"),
104
- starting_line,
105
- source_type,
106
- options)
107
- end
108
- end
109
- end
110
-
111
- # Rest of the file quite less self-explanatory
112
- def source
113
- @source
114
- end
115
-
116
- protected
117
- def comment_symbols
118
- super || {}
119
- end
120
-
121
- # Method for checking source for comments. Used for getting consequent non-comments
122
- # into resulting stream
123
- def is_comment(line)
124
- result = false
125
- # If source supports single line comments
126
- if comment_symbols[:single_line]
127
- result ||= line =~ /^\s*#{Regexp.escape(comment_symbols[:single_line])}/
128
- end
129
-
130
- # If source supports multi-line comments
131
- if comment_symbols[:multiline]
132
- result ||= line =~ /^\s*#{Regexp.escape(comment_symbols[:multiline][:begin])}/
133
- end
134
- result
135
- end
136
-
137
- #
138
- # Removes trailing spaces from comments, also removes first space from comments,
139
- # but only if there's only one space there (not to mess with markdown)
140
- #
141
- def postprocess_comments(comment_lines)
142
- comment_lines.map! {|l| l.sub(/^\s([^\s])/, '\\1').rstrip }
143
- comment_lines.delete_at(0) while comment_lines.size > 0 && comment_lines[0].empty?
144
- comment_lines.delete_at(-1) while comment_lines.size > 0 && comment_lines[-1].empty?
145
- end
146
-
147
-
148
- # Removes blank lines from beginning and end of source lines
149
- # returns starting offset for source (number of lines deleted from beginning)
150
- def postprocess_source(source_lines)
151
- starting_offset = 0
152
- while source_lines.size > 0 && source_lines[0] =~ /^\s*$/
153
- starting_offset += 1
154
- source_lines.delete_at(0)
155
- end
156
-
157
- while source_lines.size > 0 && source_lines[-1] =~ /^\s*$/
158
- source_lines.delete_at(-1)
159
- end
160
- starting_offset
38
+ @source_type = (source_type || :base).to_sym
161
39
  end
162
40
  end
163
41
  end
@@ -0,0 +1,41 @@
1
+ require 'forwardable'
2
+ module Murdoc
3
+ class FormattedParagraph
4
+ extend Forwardable
5
+
6
+ def_delegators :paragraph, :annotation, :source, :starting_line, :source_type
7
+
8
+ attr_reader :paragraph
9
+ attr_reader :highlight
10
+
11
+ def initialize(paragraph, highlight = true)
12
+ @paragraph = paragraph
13
+ @highlight = highlight
14
+ end
15
+
16
+ def formatted_annotation
17
+ if defined?(Markdown)
18
+ Markdown.new(annotation, :smart).to_html
19
+ else
20
+ Kramdown::Document.new(annotation, :input => :markdown).to_html
21
+ end
22
+ end
23
+
24
+ def formatted_source
25
+ @formatted_source ||= if pygments_installed? && highlight && source_type != :base
26
+ IO.popen("pygmentize -l #{source_type} -O encoding=UTF8 -f html -O nowrap", "w+") do |pipe|
27
+ pipe.puts source
28
+ pipe.close_write
29
+ pipe.read
30
+ end
31
+ else
32
+ CGI.escapeHTML(source)
33
+ end
34
+ end
35
+
36
+ protected
37
+ def pygments_installed?
38
+ @@pygments_installed ||= ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
39
+ end
40
+ end
41
+ end