css_doc 0.0.6

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.
data/bin/cssdoc ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'css_doc'
4
+ require 'optparse'
5
+
6
+ class CSSDocCli
7
+ def self.run(args)
8
+ options = {
9
+ :input_dir => '.',
10
+ :skip_files => [],
11
+ :output_dir => 'doc',
12
+ :template_path => File.expand_path(File.dirname(__FILE__) + "/../src/templates/default")
13
+ }
14
+ OptionParser.new do |opts|
15
+ opts.banner = "Usage: cssdoc [options] [input-dir/input-files]"
16
+ opts.on("-o", "--output=dir", "Specify output directory") do |dir|
17
+ options[:output_dir] = dir
18
+ end
19
+ opts.on("-s", "--skip=files", "Skip specified files") do |files|
20
+ options[:skip_files] = files.split(',').collect { |file| file.strip }
21
+ end
22
+ opts.on("-p", "--project-name=name", "Specify Project name") do |name|
23
+ options[:project_name] = name
24
+ end
25
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
26
+ options[:verbose] = v
27
+ end
28
+ opts.on("-t", "--template=name/path", "Specify template or template path") do |name|
29
+ if File.directory?(name)
30
+ options[:template_path] = name
31
+ else
32
+ options[:template_path] = File.expand_path(File.dirname(__FILE__) + "/../src/templates/#{name}")
33
+ end
34
+ end
35
+ end.parse!
36
+ options[:input_dir] = ARGV.first if ARGV.first
37
+
38
+ driver = CSSDoc::Driver.new
39
+ driver.run(options)
40
+ end
41
+ end
42
+
43
+ CSSDocCli.run(ARGV)
data/src/css_doc.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'csspool'
2
+
3
+ require File.dirname(__FILE__) + '/css_doc/document'
4
+ require File.dirname(__FILE__) + '/css_doc/document_handler'
5
+ require File.dirname(__FILE__) + '/css_doc/document_collection'
6
+ require File.dirname(__FILE__) + '/css_doc/section'
7
+ require File.dirname(__FILE__) + '/css_doc/rule_set'
8
+ require File.dirname(__FILE__) + '/css_doc/template'
9
+ require File.dirname(__FILE__) + '/css_doc/documentation'
10
+ require File.dirname(__FILE__) + '/css_doc/document_documentation'
11
+ require File.dirname(__FILE__) + '/css_doc/rule_set_documentation'
12
+ require File.dirname(__FILE__) + '/css_doc/section_documentation'
13
+ require File.dirname(__FILE__) + '/css_doc/css_writer'
14
+ require File.dirname(__FILE__) + '/css_doc/driver'
15
+ require File.dirname(__FILE__) + '/css_doc/examples'
16
+ require File.dirname(__FILE__) + '/css_pool/visitors/to_css'
@@ -0,0 +1,20 @@
1
+ module CSSDoc
2
+ class CSSWriter
3
+ def initialize(collection)
4
+ @collection = collection
5
+ end
6
+
7
+ def write
8
+ output = ""
9
+ @collection.rule_sets.each do |rule_set|
10
+ selectors = rule_set.selectors.collect { |selector| 'div.example ' + selector.to_css }
11
+ output << selectors.join(', ')
12
+ output << '{'
13
+ output << rule_set.declaration_css
14
+ output << '}'
15
+ output << "\n"
16
+ end
17
+ output
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module CSSDoc
2
+ class Document < CSSPool::CSS::Document
3
+ attr_accessor :documentation
4
+ attr_accessor :sections
5
+ attr_accessor :name
6
+
7
+ def self.parse string, name
8
+ unless string && string.length > 0
9
+ return CSSDoc::Document.new(name)
10
+ end
11
+ handler = CSSDoc::DocumentHandler.new(name)
12
+ parser = CSSPool::SAC::Parser.new(handler)
13
+ parser.parse(string)
14
+ handler.document
15
+ end
16
+
17
+ def initialize(name)
18
+ super()
19
+ @name = name
20
+ @sections = [Section.new(self, '')]
21
+ end
22
+
23
+ def output_file_name
24
+ name.gsub('.css', '_css.html')
25
+ end
26
+
27
+ def named_sections
28
+ sections.reject {|section| section.name.nil?}
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ module CSSDoc
2
+ class DocumentCollection < CSSPool::CSS::Document
3
+ attr_accessor :documents
4
+
5
+ def initialize
6
+ @documents = []
7
+ end
8
+
9
+ def rule_sets
10
+ documents.collect { |document| document.rule_sets }.flatten
11
+ end
12
+
13
+ def selectors
14
+ rule_sets.collect { |rule_set| rule_set.selectors }.flatten
15
+ end
16
+
17
+ def sections
18
+ documents.collect { |document| document.sections }.flatten
19
+ end
20
+
21
+ def named_sections
22
+ sections.reject { |section| section.name.nil? }
23
+ end
24
+
25
+ def selector_hash
26
+ selectors.inject({}) { |hash, selector| (hash[selector.to_css] ||= []) << selector; hash }
27
+ end
28
+
29
+ def section_hash
30
+ named_sections.inject({}) { |hash, section| (hash[section.name] ||= []) << section; hash }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ module CSSDoc
2
+ class DocumentDocumentation < Documentation
3
+ define_tag :file, :note, :appdef, :link, :copyright, :author, :css_for, :version, :date, :license
4
+ end
5
+ end
@@ -0,0 +1,36 @@
1
+ module CSSDoc
2
+ class DocumentHandler < CSSPool::CSS::DocumentHandler
3
+ def initialize(name)
4
+ super()
5
+ @name = name
6
+ end
7
+
8
+ def start_document
9
+ @document = CSSDoc::Document.new(@name)
10
+ end
11
+
12
+ def comment(comment)
13
+ if comment =~ /@file/
14
+ @document.documentation = DocumentDocumentation.new(comment)
15
+ elsif comment =~ /@section/
16
+ @document.sections << Section.new(@document, comment)
17
+ else
18
+ @last_comment = comment
19
+ end
20
+ end
21
+
22
+ def start_selector(selector_list)
23
+ rule_set = CSSDoc::RuleSet.new(
24
+ selector_list,
25
+ [],
26
+ @media_stack.last || []
27
+ )
28
+ rule_set.document = @document
29
+ rule_set.documentation = RuleSetDocumentation.new(@last_comment =~ /^\*/ ? @last_comment : "")
30
+ @last_comment = nil
31
+
32
+ @document.rule_sets << rule_set
33
+ @document.sections.last.rule_sets << rule_set
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,111 @@
1
+ module CSSDoc
2
+ class Documentation
3
+ class Section
4
+ attr_accessor :lines
5
+ def initialize(lines)
6
+ self.lines = lines
7
+ end
8
+
9
+ def to_s
10
+ lines.join("\n")
11
+ end
12
+ end
13
+
14
+ class TextSection < Section
15
+ def to_html
16
+ result = "<p>"
17
+ result << lines.collect {|l|l.strip}.join("\n").gsub(/\n\n+/, '</p><p>').gsub(/\n/, ' ').strip
18
+ result << "</p>"
19
+ result.gsub('<p></p>', '')
20
+ end
21
+ end
22
+
23
+ class CodeSection < Section
24
+ def to_html
25
+ result = "<pre>" + lines.join("\n").gsub("<", "&lt;").gsub(">", "&gt;").gsub('"', '&quot;') + "</pre>"
26
+ result << %{<div class="example">#{lines.join("\n")}</div>}
27
+ end
28
+ end
29
+
30
+ class Sections < Array
31
+ def to_html
32
+ collect {|section| section.to_html}
33
+ end
34
+ end
35
+
36
+ attr_accessor :comment
37
+ attr_accessor :sections
38
+
39
+ def self.tags
40
+ @tags ||= []
41
+ end
42
+
43
+ def self.define_tag(*names)
44
+ names.each do |name|
45
+ attr_accessor name
46
+ tags << name
47
+ end
48
+ end
49
+
50
+ def initialize(comment)
51
+ @comment = comment
52
+ @sections = Sections.new
53
+ parse_documentation
54
+ end
55
+
56
+ def to_s
57
+ @comment
58
+ end
59
+
60
+ def parse_tags(line)
61
+ self.class.tags.each do |tag|
62
+ rx = /@#{tag.to_s.gsub('_', '-')}/
63
+ if line =~ rx
64
+ instance_variable_set(:"@#{tag}", line.gsub(rx, "").strip)
65
+ return true
66
+ end
67
+ end
68
+ return false
69
+ end
70
+
71
+ def parse_comment
72
+ @parsed_comment ||= comment.gsub(/\*\/$/, '').split("\n").collect { |line| line.gsub(/^\s*\*/, '') }
73
+ end
74
+
75
+ def parse_documentation
76
+ lines = parse_comment
77
+ parse(lines)
78
+ end
79
+
80
+ def empty?
81
+ parse_comment.join("\n").strip.empty?
82
+ end
83
+
84
+ def parse(lines)
85
+ section_type = TextSection
86
+ section_text = []
87
+ lines.each do |line|
88
+ unless parse_tags(line)
89
+ if line =~ /@code/
90
+ sections << section_type.new(section_text)
91
+ section_text = []
92
+ section_type = CodeSection
93
+ elsif line =~ /@endcode/
94
+ sections << section_type.new(section_text)
95
+ section_text = []
96
+ section_type = TextSection
97
+ elsif line =~ /@description/
98
+ section_text << line.gsub(/@description/, '')
99
+ else
100
+ section_text << line
101
+ end
102
+ end
103
+ end
104
+ sections << section_type.new(section_text)
105
+
106
+ sections.each do |section|
107
+ Examples.add(section) if section.is_a?(CodeSection)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,85 @@
1
+ require 'fileutils'
2
+
3
+ module CSSDoc
4
+ class Driver
5
+ def run(options = {})
6
+ @options = options
7
+
8
+ @collection = CSSDoc::DocumentCollection.new
9
+
10
+ generate_file_documentation
11
+ generate_index_documentation
12
+ generate_css
13
+ copy_additional_files
14
+ end
15
+
16
+ def generate_file_documentation
17
+ skip_files = @options[:skip_files] || []
18
+
19
+ Dir.glob("#{@options[:input_dir]}/**/*.css").each do |file_name|
20
+ relative_path = file_name.gsub("#{@options[:input_dir]}/", '')
21
+ next if skip_files.include?(relative_path)
22
+
23
+ log "Generating documentation for file #{relative_path} ..."
24
+
25
+ FileUtils.mkdir_p("#{@options[:output_dir]}/#{File.dirname(relative_path)}")
26
+ doc = CSSDoc::Document.parse(File.read(file_name), relative_path)
27
+
28
+ generate(:template => 'document', :file_name => doc.output_file_name, :locals => { :document => doc, :title => doc.name })
29
+
30
+ @collection.documents << doc
31
+ end
32
+ end
33
+
34
+ def generate_index_documentation
35
+ log "Generating Selector Index ..."
36
+
37
+ generate(:template => 'selector_index', :locals => { :collection => @collection, :title => 'Selector Index' })
38
+
39
+ log "Generating File Index ..."
40
+
41
+ generate(:template => 'file_index', :locals => { :collection => @collection, :title => 'File Index' })
42
+
43
+ log "Generating Section Index ..."
44
+
45
+ generate(:template => 'section_index', :locals => { :collection => @collection, :title => 'Section Index' })
46
+
47
+ log "Generating Example Index ..."
48
+
49
+ generate(:template => 'example_index', :locals => { :collection => @collection, :title => 'Example Index' })
50
+
51
+ log "Generating Index Page ..."
52
+
53
+ generate(:template => 'index', :locals => { :project_name => @options[:project_name], :title => 'Index' })
54
+ end
55
+
56
+ def generate_css
57
+ log "Generating Example CSS ..."
58
+
59
+ writer = CSSDoc::CSSWriter.new(@collection)
60
+ File.open("#{@options[:output_dir]}/styles.css", 'w') { |file| file.puts writer.write }
61
+ end
62
+
63
+ def copy_additional_files
64
+ log "Copying Additional Files ..."
65
+
66
+ FileUtils.cp("#{@options[:template_path]}/css_doc.css", "#{@options[:output_dir]}/")
67
+ end
68
+
69
+ def log(string)
70
+ puts string if @options[:verbose]
71
+ end
72
+
73
+ private
74
+ def generate(params)
75
+ file_name = params[:file_name] || params[:template]
76
+ file_name += '.html' unless file_name =~ /\.html$/
77
+
78
+ relative_root = '.'
79
+ relative_root = (['..'] * File.dirname(file_name).split('/').size).join('/') if file_name =~ /\//
80
+
81
+ html = CSSDoc::Template.new(@options.merge(:relative_root => relative_root)).render(params[:template], params[:locals])
82
+ File.open("#{@options[:output_dir]}/#{file_name}", 'w') { |file| file.puts html }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,12 @@
1
+ module CSSDoc
2
+ class Examples
3
+ def self.add(code)
4
+ @examples ||= []
5
+ @examples << code
6
+ end
7
+
8
+ def self.all
9
+ @examples
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module CSSDoc
2
+ class RuleSet < CSSPool::CSS::RuleSet
3
+ attr_accessor :document
4
+ attr_accessor :documentation
5
+
6
+ def selector_css
7
+ @selector_css ||= selectors.collect { |selector| selector.to_css }.join(", ")
8
+ end
9
+
10
+ def declaration_css
11
+ @declaration_css ||= declarations.collect { |declaration| declaration.to_css }.join(' ')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ module CSSDoc
2
+ class RuleSetDocumentation < Documentation
3
+ define_tag :name, :formerly, :deprecated
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ module CSSDoc
2
+ class Section
3
+ attr_accessor :document
4
+ attr_accessor :rule_sets
5
+ attr_accessor :documentation
6
+
7
+ def initialize(document, comment)
8
+ @document = document
9
+ @rule_sets = []
10
+ @documentation = SectionDocumentation.new(comment)
11
+ end
12
+
13
+ def name
14
+ documentation.section
15
+ end
16
+ end
17
+ end