murdoc 0.1.13 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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