adocsite 1.0.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.
Files changed (44) hide show
  1. data/.gitignore +21 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +82 -0
  5. data/Rakefile +1 -0
  6. data/TODO.md +12 -0
  7. data/adocsite.gemspec +32 -0
  8. data/bin/adocsite +63 -0
  9. data/examples/myconfig.rb +7 -0
  10. data/examples/mywpconfig.rb +9 -0
  11. data/lib/adocsite.rb +35 -0
  12. data/lib/adocsite/commands.rb +83 -0
  13. data/lib/adocsite/config.rb +66 -0
  14. data/lib/adocsite/content_loader.rb +59 -0
  15. data/lib/adocsite/content_types.rb +60 -0
  16. data/lib/adocsite/context.rb +118 -0
  17. data/lib/adocsite/engine.rb +147 -0
  18. data/lib/adocsite/site.rb +49 -0
  19. data/lib/adocsite/templates.rb +91 -0
  20. data/lib/adocsite/version.rb +3 -0
  21. data/lib/adocsite/wp/post.rb +170 -0
  22. data/tpl/default/includes/anything.haml +2 -0
  23. data/tpl/default/includes/bottom.haml +2 -0
  24. data/tpl/default/includes/footer.haml +4 -0
  25. data/tpl/default/includes/header.haml +2 -0
  26. data/tpl/default/includes/menu.haml +9 -0
  27. data/tpl/default/includes/one_level_menu.haml +5 -0
  28. data/tpl/default/includes/top.haml +2 -0
  29. data/tpl/default/layouts/compact.haml +14 -0
  30. data/tpl/default/layouts/default.haml +14 -0
  31. data/tpl/default/literals/google_analytics +7 -0
  32. data/tpl/default/partials/article.haml +2 -0
  33. data/tpl/default/partials/category.haml +6 -0
  34. data/tpl/default/partials/home.haml +12 -0
  35. data/tpl/default/partials/page.haml +2 -0
  36. data/tpl/default/resources/asciidoc.js +189 -0
  37. data/tpl/default/resources/asciidoctor.css +351 -0
  38. data/tpl/default/resources/funky.css +0 -0
  39. data/tpl/default/resources/kernel.css +0 -0
  40. data/tpl/default/resources/myblueraven.css +11 -0
  41. data/tpl/default/resources/myblueraven.js +0 -0
  42. data/tpl/default/resources/old-myblueraven.css +1316 -0
  43. data/tpl/default/resources/sleepy.js +0 -0
  44. metadata +201 -0
@@ -0,0 +1,59 @@
1
+ module Adocsite
2
+ class ContentLoader
3
+ attr_reader :styles, :scripts, :images, :files, :pages, :articles
4
+ def initialize
5
+ @adoc_options = {:attributes => {
6
+ "imagesdir" => Adocsite::config[:IMAGES_FOLDER],
7
+ "stylesdir" => Adocsite::config[:STYLES_FOLDER],
8
+ "iconsdir" => Adocsite::config[:IMAGES_FOLDER] + "/icons"
9
+ }}
10
+
11
+ # files to copy
12
+ @styles = Array.new
13
+ @scripts = Array.new
14
+ @images = Array.new
15
+ @files = Array.new
16
+
17
+ #content
18
+ @pages = Hash.new
19
+ @articles = Hash.new
20
+ end
21
+
22
+ def find_all_files
23
+ file_list = []
24
+ Adocsite::config[:INPUT_FOLDERS].each {|input_folder|
25
+ file_list.concat(Dir[File.join(input_folder, "**","*")].reject {|x| File.directory?(x)})
26
+ }
27
+ return file_list
28
+ end
29
+
30
+ def load_assets
31
+ all_files = find_all_files
32
+
33
+ @content = all_files.select {|path| path.end_with?(*Adocsite::config[:DOCUMENTS])}
34
+
35
+ @styles = all_files.select {|path| path.end_with?(*Adocsite::config[:STYLES])}
36
+ @scripts = all_files.select {|path| path.end_with?(*Adocsite::config[:SCRIPTS])}
37
+ @images = all_files.select {|path| path.end_with?(*Adocsite::config[:IMAGES])}
38
+ @files = all_files - @images - @scripts - @styles - @content
39
+
40
+ build_pages_and_articles
41
+ end
42
+
43
+ def build_pages_and_articles
44
+ @content.each {|path|
45
+ adoc = Asciidoctor::load_file(path, @adoc_options)
46
+ if adoc.attributes["page"].nil?
47
+ article = Article.new(adoc)
48
+ @articles[article.name] = article
49
+ else
50
+ page = Page.new(adoc)
51
+ @pages[page.name] = page
52
+ end
53
+ }
54
+
55
+ end
56
+
57
+ private :build_pages_and_articles, :find_all_files
58
+ end
59
+ end
@@ -0,0 +1,60 @@
1
+ module Adocsite
2
+ class Content
3
+ attr_reader :name, :title
4
+ def initialize(adoc)
5
+ @name = Content::title_to_name(adoc.doctitle)
6
+ @title = adoc.doctitle
7
+ @content = adoc.content
8
+ end
9
+
10
+ def self.title_to_name(title)
11
+ title = title.strip
12
+ title = title.gsub(/[^0-9A-Za-z.\-]/, '_')
13
+ title = title.gsub(/[_]+/, '_')
14
+ end
15
+
16
+ def stringreturn(title, link_text)
17
+ link_text = link_text.empty? ? title : link_text
18
+ '<a href="'+Content::title_to_name(title)+'.html">'+link_text+'</a>'
19
+ end
20
+
21
+ def content()
22
+ @content = @content.gsub(/sitenav:['"](.*)['"](\[(.*)\])?/) {|sitenav| stringreturn("#$1","#$3")}
23
+ end
24
+
25
+ private :stringreturn
26
+ end
27
+
28
+ class Article < Content
29
+ UNCATEGORIZED_NAME = 'Uncategorized'
30
+ attr_reader :categories, :abstract
31
+ def initialize(adoc)
32
+ super(adoc)
33
+ @abstract = ''
34
+ idx = adoc.blocks.index {|block| block.context==:preamble}
35
+ if idx
36
+ @abstract = adoc.blocks[idx].content
37
+ end
38
+ @categories = Array.new
39
+ if adoc.attributes['categories'] != nil
40
+ @categories = CSV.parse_line(adoc.attributes['categories'].gsub(/,\s+"/,',"'))
41
+ else
42
+ @categories << UNCATEGORIZED_NAME
43
+ end
44
+ @categories.each_index {|cat_idx|
45
+ @categories[cat_idx] = @categories[cat_idx].strip
46
+ }
47
+ end
48
+ end
49
+
50
+ class Category
51
+ attr_reader :name, :articles
52
+ def initialize(name, articles)
53
+ @name = name
54
+ @articles = articles
55
+ end
56
+ end
57
+
58
+ class Page < Content
59
+ end
60
+ end
@@ -0,0 +1,118 @@
1
+ module Adocsite
2
+ class Context
3
+ attr_reader :type
4
+ def initialize(engine, request)
5
+ @engine = engine
6
+ @request = request
7
+ @type = request.type
8
+ @context_vars = Hash.new
9
+
10
+ build_vars
11
+ end
12
+
13
+ def build_vars()
14
+ # variables common to all contexts
15
+ @context_vars = {
16
+ :page_title => Adocsite::config[:SITE_TITLE],
17
+ }
18
+
19
+ if @type == "home"
20
+ # @context_vars[] = 'nil'
21
+ elsif @type == "page"
22
+ @context_vars[:page] = get_page
23
+ elsif @type == "article"
24
+ @context_vars[:article] = get_article
25
+ elsif @type == "category"
26
+ @context_vars[:category] = get_category
27
+ end
28
+ end
29
+
30
+ #--------------------------------------------------
31
+ # these methods load other templates and render them
32
+ # in the same context in which current document is rendered
33
+ def get_partial(partial_name)
34
+ tpl = @engine.templates.get_partial(partial_name)
35
+ tpl.render(self, @context_vars)
36
+ end
37
+
38
+ def get_include(include_name)
39
+ tpl = @engine.templates.get_include(include_name)
40
+ tpl.render(self, @context_vars)
41
+ end
42
+
43
+ def get_literal(literal_name)
44
+ @engine.templates.get_literal(literal_name)
45
+ end
46
+
47
+ def get_layout(layout_name = "default")
48
+ tpl = @engine.templates.get_layout(layout_name)
49
+ tpl.render(self, @context_vars)
50
+ end
51
+ #--------------------------------------------------
52
+
53
+ #--------------------------------------------------
54
+ # these methods behave the same in all contexts
55
+ # they are context independet
56
+ def is_context?(context_name)
57
+ @type == context_name
58
+ end
59
+
60
+ def get_pages()
61
+ @engine.content_loader.pages.values
62
+ end
63
+
64
+ def get_categories()
65
+ @engine.categories.values
66
+ end
67
+
68
+ def get_articles(category = nil)
69
+ if category
70
+ @engine.categories[category]
71
+ else
72
+ @engine.content_loader.articles.values
73
+ end
74
+ end
75
+
76
+ def sitenav(type, name)
77
+ request = Request.new(type, name)
78
+ @engine.sitenav(request)
79
+ end
80
+ #--------------------------------------------------
81
+
82
+ #--------------------------------------------------
83
+ # this is special kind of method that is used in layout template.
84
+ # it gets correct partial for the layout depending on context.
85
+ def get_content_for_layout()
86
+ get_partial(@type)
87
+ # if @type == "home"
88
+ # get_partial('home')
89
+ # elsif @type == "page"
90
+ # get_partial('page')
91
+ # elsif @type == "article"
92
+ # get_partial('article')
93
+ # elsif @type == "category"
94
+ # get_partial('category')
95
+ # end
96
+ end
97
+ #--------------------------------------------------
98
+
99
+ #--------------------------------------------------
100
+ # result of calling these depends on context in which
101
+ # they are used, it depends on request that is made
102
+ def get_article()
103
+ @engine.content_loader.articles[@request.name]
104
+ end
105
+
106
+ def get_category()
107
+ @engine.categories[@request.name]
108
+ end
109
+
110
+ def get_page()
111
+ @engine.content_loader.pages[@request.name]
112
+ end
113
+ #--------------------------------------------------
114
+
115
+ private :build_vars
116
+
117
+ end
118
+ end
@@ -0,0 +1,147 @@
1
+ module Adocsite
2
+ class Request
3
+ attr_reader :type, :name
4
+ def initialize(type = 'home', name = 'index')
5
+ @type = type
6
+ @name = name
7
+ end
8
+ end
9
+
10
+ class RequestProcessing
11
+ attr_accessor :rendered
12
+ attr_reader :request
13
+ def initialize(request)
14
+ @request = request
15
+ rendered = false
16
+ end
17
+ end
18
+
19
+ class Engine
20
+ LINK_DOCUMENT_EXTENSION = '.html'
21
+ OUTPUT_DOCUMENT_EXTENSION = '.html'
22
+ LOCATION_PAGE = ''
23
+ LOCATION_ARTICLE = ''
24
+ LOCATION_CATEGORY = ''
25
+ attr_reader :content_loader, :templates, :categories
26
+ def initialize
27
+ # Internal stuff
28
+ @page_context = Array.new
29
+ @request_processing_queue = Hash.new
30
+
31
+ # This is hashmap of Category objects.
32
+ @categories = Hash.new
33
+
34
+ @content_loader = ContentLoader.new
35
+ @content_loader.load_assets
36
+
37
+ @templates = Templates.new
38
+ @templates.load_assets
39
+
40
+ build_categories
41
+
42
+ @site = Site.new(self)
43
+ @site.prepare_output
44
+ @site.copy_content
45
+ end
46
+
47
+ def build_categories
48
+ # figure out categories and build hash of (category, articles)
49
+ @categories = Hash.new
50
+ @content_loader.articles.values.each {|article|
51
+ article_title = article.title
52
+
53
+ article.categories.each_index {|idx|
54
+ cat = article.categories[idx]
55
+ if @categories[cat] == nil
56
+ @categories[cat] = Category.new(cat, [article])
57
+ else
58
+ @categories[cat].articles.push(article)
59
+ end
60
+ }
61
+ }
62
+ end
63
+
64
+ def request_process_key(request)
65
+ request.type + ':' + request.name
66
+ end
67
+
68
+ def add_to_processing_queue(request)
69
+ # Add request into processing queue if it is not already there
70
+ rp_key = request_process_key(request)
71
+ if @request_processing_queue[rp_key] == nil
72
+ @request_processing_queue[rp_key] = RequestProcessing.new(request)
73
+ end
74
+ return rp_key
75
+ end
76
+
77
+ def get_next_from_processing_queue
78
+ if @request_processing_queue.empty?
79
+ nil
80
+ else
81
+ # Find first element that is not yet processed
82
+ idx = @request_processing_queue.values.index {|request_processing| !request_processing.rendered}
83
+ if idx
84
+ @request_processing_queue.values[idx]
85
+ else
86
+ nil
87
+ end
88
+ end
89
+ end
90
+
91
+ def process_requests(layout)
92
+ # Get request from queue
93
+
94
+ # request_processing = get_next_from_processing_queue
95
+
96
+ while request_processing = get_next_from_processing_queue
97
+ a_request = request_processing.request
98
+ puts "Processing - '" + a_request.name + "'..."
99
+ # Process request, which means render and save output
100
+ context = Context.new(self, a_request)
101
+
102
+ # this converts request into html page
103
+ # all the heavy lifting is hidden behind this call
104
+ output = context.get_layout(layout)
105
+ # save it, nah?
106
+ @site.write(output, a_request.name + OUTPUT_DOCUMENT_EXTENSION)
107
+
108
+ # Mark this one as done
109
+ request_processing.rendered = true
110
+ end
111
+ end
112
+
113
+ def build(layout = "default")
114
+ home = Request.new
115
+ add_to_processing_queue(home)
116
+ process_requests(layout)
117
+ end
118
+
119
+ def sitenav(request)
120
+ # remember to actually generate this document later
121
+ add_to_processing_queue(request)
122
+
123
+ # now just create link text and return it to caller
124
+ site_root = Adocsite::config[:SITE_URL]
125
+ if request.type == "home"
126
+ path = '/'
127
+ elsif request.type == "page"
128
+ path = LOCATION_PAGE + request.name + LINK_DOCUMENT_EXTENSION
129
+ elsif request.type == "article"
130
+ path = LOCATION_ARTICLE + request.name + LINK_DOCUMENT_EXTENSION
131
+ elsif request.type == "category"
132
+ path = LOCATION_CATEGORY + request.name + LINK_DOCUMENT_EXTENSION
133
+ else
134
+ path = ''
135
+ end
136
+ if site_root.empty?
137
+ path
138
+ else
139
+ URI::HTTP.build({:host => site_root, :path => path})
140
+ end
141
+ end
142
+
143
+ private :build_categories, :request_process_key, :process_requests, :add_to_processing_queue
144
+
145
+ end
146
+
147
+ end
@@ -0,0 +1,49 @@
1
+ module Adocsite
2
+ class Site
3
+ attr_reader :styles, :scripts, :images, :files
4
+ def initialize(engine)
5
+ # Internal
6
+ @engine = engine
7
+
8
+ # files to copy
9
+ @styles = Array.new
10
+ @scripts = Array.new
11
+ @images = Array.new
12
+ @files = Array.new
13
+ end
14
+
15
+ def prepare_output
16
+ output_folder = File.join(Adocsite::config[:OUTPUT_FOLDER])
17
+ Dir.mkdir(output_folder) unless Dir.exists?(output_folder)
18
+ FileUtils.rm_rf(Dir.glob(File.join(output_folder,'*')))
19
+ end
20
+
21
+ def write(content, name)
22
+ f = File.new(File.join(Adocsite::config[:OUTPUT_FOLDER], name), "w")
23
+ f.write(content)
24
+ f.close()
25
+ end
26
+
27
+ def copy_content
28
+ styles_folder = File.join(Adocsite::config[:OUTPUT_FOLDER], Adocsite::config[:STYLES_FOLDER])
29
+ images_folder = File.join(Adocsite::config[:OUTPUT_FOLDER], Adocsite::config[:IMAGES_FOLDER])
30
+ scripts_folder = File.join(Adocsite::config[:OUTPUT_FOLDER], Adocsite::config[:SCRIPTS_FOLDER])
31
+ files_folder = File.join(Adocsite::config[:OUTPUT_FOLDER])
32
+
33
+ Dir.mkdir(files_folder) unless Dir.exists?(files_folder)
34
+ Dir.mkdir(styles_folder) unless Dir.exists?(styles_folder)
35
+ Dir.mkdir(scripts_folder) unless Dir.exists?(scripts_folder)
36
+ Dir.mkdir(images_folder) unless Dir.exists?(images_folder)
37
+
38
+ FileUtils.copy(@engine.content_loader.styles, styles_folder)
39
+ FileUtils.copy(@engine.content_loader.scripts, scripts_folder)
40
+ FileUtils.copy(@engine.content_loader.images, images_folder)
41
+ FileUtils.copy(@engine.content_loader.files, files_folder)
42
+
43
+ FileUtils.copy(@engine.templates.styles, styles_folder)
44
+ FileUtils.copy(@engine.templates.scripts, scripts_folder)
45
+ FileUtils.copy(@engine.templates.images, images_folder)
46
+ FileUtils.copy(@engine.templates.files, files_folder)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,91 @@
1
+ module Adocsite
2
+ class Templates
3
+ attr_reader :styles, :scripts, :images, :files, :layouts, :partials, :includes, :literals
4
+ def initialize
5
+ @options = {:remove_whitespace => true}
6
+ # files to copy
7
+ @styles = Array.new
8
+ @scripts = Array.new
9
+ @images = Array.new
10
+ @files = Array.new
11
+
12
+ # theme template files
13
+ # hashmap keys are template names without .haml extension and values are full paths
14
+ # literal names are full file names (without path portion) and values are full paths
15
+ @layouts = Hash.new
16
+ @partials = Hash.new
17
+ @includes = Hash.new
18
+ @literals = Hash.new
19
+ end
20
+
21
+ def find_all_files
22
+ Dir[File.join(Adocsite::config[:TEMPLATES_FOLDER], "**","*")].reject {|x| File.directory?(x)}
23
+ end
24
+
25
+ def load_assets
26
+ all_files = find_all_files
27
+
28
+ templates = all_files.select {|path| path.end_with?(*Adocsite::config[:TEMPLATES])}
29
+
30
+ @styles = all_files.select {|path| path.end_with?(*Adocsite::config[:STYLES])}
31
+ @scripts = all_files.select {|path| path.end_with?(*Adocsite::config[:SCRIPTS])}
32
+ @images = all_files.select {|path| path.end_with?(*Adocsite::config[:IMAGES])}
33
+ @files = all_files - @images - @scripts - @styles - templates
34
+
35
+ # loads layouts, partials, includes and literals into hashmaps.
36
+ # hashmap keys are template names without .haml extension and values are full paths
37
+ # literal names are full file names (without path portion) and values are full paths
38
+ theme_location = File.join(Adocsite::config[:TEMPLATES_FOLDER], Adocsite::config[:THEME])
39
+ layouts = templates.select {|path| path.start_with?(File.join(theme_location, "layouts")) }
40
+ layouts.each {|layout|
41
+ layout_name = File.basename(layout, '.*')
42
+ @layouts[layout_name] = layout
43
+ }
44
+ partials = templates.select {|path| path.start_with?(File.join(theme_location, "partials")) }
45
+ partials.each {|partial|
46
+ partial_name = File.basename(partial, '.*')
47
+ @partials[partial_name] = partial
48
+ }
49
+ includes = templates.select {|path| path.start_with?(File.join(theme_location, "includes")) }
50
+ includes.each {|include|
51
+ include_name = File.basename(include, '.*')
52
+ @includes[include_name] = include
53
+ }
54
+ literals = @files.select {|path| path.start_with?(File.join(theme_location, "literals")) }
55
+ literals.each {|literal|
56
+ literal_name = File.basename(literal)
57
+ @literals[literal_name] = literal
58
+ }
59
+ @files = @files - literals
60
+ all_files
61
+ end
62
+
63
+ def get_partial(partial_name)
64
+ partial_tpl = @partials[partial_name]
65
+ tpl = Tilt.new(partial_tpl, @options)
66
+ return tpl
67
+ end
68
+
69
+ def get_include(include_name)
70
+ include_tpl = @includes[include_name]
71
+ tpl = Tilt.new(include_tpl, @options)
72
+ return tpl
73
+ end
74
+
75
+ def get_literal(literal_name)
76
+ literal_tpl = @literals[literal_name]
77
+ # literals are not processed, they are literals
78
+ tpl = File.read(literal_tpl)
79
+ return tpl
80
+ end
81
+
82
+ def get_layout(layout_name = "default")
83
+ layout_tpl = @layouts[layout_name]
84
+ tpl = Tilt.new(layout_tpl, @options)
85
+ return tpl
86
+ end
87
+
88
+ private :find_all_files
89
+
90
+ end
91
+ end