css_doc 0.0.6

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