marsdawn 0.0.1

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 (71) hide show
  1. checksums.yaml +15 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +20 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +119 -0
  8. data/Rakefile +12 -0
  9. data/bin/marsdawn +6 -0
  10. data/lib/marsdawn/builder.rb +35 -0
  11. data/lib/marsdawn/command.rb +154 -0
  12. data/lib/marsdawn/config.rb +31 -0
  13. data/lib/marsdawn/search/rroonga.rb +83 -0
  14. data/lib/marsdawn/search.rb +16 -0
  15. data/lib/marsdawn/site/breadcrumb.rb +30 -0
  16. data/lib/marsdawn/site/indexer.rb +78 -0
  17. data/lib/marsdawn/site/link.rb +28 -0
  18. data/lib/marsdawn/site/page.rb +118 -0
  19. data/lib/marsdawn/site/page_nav.rb +24 -0
  20. data/lib/marsdawn/site/search_box.rb +27 -0
  21. data/lib/marsdawn/site/search_page.rb +35 -0
  22. data/lib/marsdawn/site.rb +70 -0
  23. data/lib/marsdawn/source/document.rb +36 -0
  24. data/lib/marsdawn/source/front_matter.rb +25 -0
  25. data/lib/marsdawn/source/kramdown/parser.rb +56 -0
  26. data/lib/marsdawn/source.rb +164 -0
  27. data/lib/marsdawn/storage/active_record/marsdawn.rb +20 -0
  28. data/lib/marsdawn/storage/active_record.rb +83 -0
  29. data/lib/marsdawn/storage/base.rb +44 -0
  30. data/lib/marsdawn/storage/file_system.rb +83 -0
  31. data/lib/marsdawn/storage/redis.rb +0 -0
  32. data/lib/marsdawn/storage/test.rb +20 -0
  33. data/lib/marsdawn/storage/test_not_implemented_error.rb +6 -0
  34. data/lib/marsdawn/storage.rb +22 -0
  35. data/lib/marsdawn/util.rb +39 -0
  36. data/lib/marsdawn/version.rb +3 -0
  37. data/lib/marsdawn.rake +9 -0
  38. data/lib/marsdawn.rb +55 -0
  39. data/marsdawn.gemspec +25 -0
  40. data/spec/_compiled_doc/.gitkeep +0 -0
  41. data/spec/_test_doc/config.yml +10 -0
  42. data/spec/_test_doc/docs01/.index.md +1 -0
  43. data/spec/_test_doc/docs01/.marsdawn.yml +4 -0
  44. data/spec/_test_doc/docs01/010_about.md +4 -0
  45. data/spec/_test_doc/docs01/020_tutorial/.index.md +0 -0
  46. data/spec/_test_doc/docs01/020_tutorial/010_install.md +6 -0
  47. data/spec/_test_doc/docs01/020_tutorial/020_getting_start.md +9 -0
  48. data/spec/_test_doc/docs01/030_reference/1up.md +0 -0
  49. data/spec/_test_doc/docs01/030_reference/each.md +0 -0
  50. data/spec/_test_doc/docs01/030_reference/z-index.md +0 -0
  51. data/spec/_test_doc/docs01/040_appendix.md +3 -0
  52. data/spec/_test_doc/no_config/.gitkeep +0 -0
  53. data/spec/_test_doc/no_key/.marsdawn.yml +3 -0
  54. data/spec/_test_doc/samples/010_sample-document.md +4 -0
  55. data/spec/_test_doc/samples/test_document.md +1 -0
  56. data/spec/_tmp/.gitkeep +0 -0
  57. data/spec/lib/marsdawn/command_spec.rb +144 -0
  58. data/spec/lib/marsdawn/config_spec.rb +41 -0
  59. data/spec/lib/marsdawn/site/page_spec.rb +122 -0
  60. data/spec/lib/marsdawn/site_spec.rb +67 -0
  61. data/spec/lib/marsdawn/source/document_spec.rb +178 -0
  62. data/spec/lib/marsdawn/source/front_matter_spec.rb +55 -0
  63. data/spec/lib/marsdawn/source_spec.rb +40 -0
  64. data/spec/lib/marsdawn/storage/active_record_spec.rb +47 -0
  65. data/spec/lib/marsdawn/storage/file_system_spec.rb +46 -0
  66. data/spec/lib/marsdawn/storage_spec.rb +29 -0
  67. data/spec/lib/marsdawn/util_spec.rb +57 -0
  68. data/spec/spec_helper.rb +12 -0
  69. data/spec/stubs/groonga.rb +17 -0
  70. data/spec/stubs/marsdawn_docs.rb +40 -0
  71. metadata +203 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NTI0YWM4Nzg0OWIxYTBiZmM3MjIyZjVjN2U0Yjg3N2FhY2YzZWMzYg==
5
+ data.tar.gz: !binary |-
6
+ NzAzOTEyZTkwNWNkZjQ2ZjQwMGExOTk1YzNmYTA2MGJlNTNhOTE2OQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MTJiMDlmODk3MGU5MmI1OTRmOWQ2NWE3MjA4YmUyODA5MDIzNGEzODU3OGU3
10
+ ZjE2Mzg5OTk1MDRjZTY0YWI4NTI2YTVlMDZhN2EzMmVjYzZlNmQ0OTZmYWVi
11
+ Nzg1YzEzMTc0YWMxYjBlZGY5ZjZiYmU0Y2U1YTRmNWFiMjA5ZDY=
12
+ data.tar.gz: !binary |-
13
+ OGE0YzBiYmFiYzY1NGEyMzAzOTc5ZjU1Mzg1Y2Y1ZjNjZDJmZjI2MGNhZTJi
14
+ OWJmOWVhZGQ4ODgwYjljNzc2ZmUzYWZhZGNhZTM0OGVkOTE1MDU3NzhhYjAx
15
+ Y2FjNmI5MWUwYjNkMDE4OWRlMGVkNTczZGU5ODJiZTk0MDMxMDY=
data/.coveralls.yml ADDED
@@ -0,0 +1,2 @@
1
+ service_name: travis-ci
2
+ repo_token: rh7Ee5DRpsg5CVHPPCrj07cAUyIqsnWiI
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ vendor
19
+ spec/_compiled_doc/*/
20
+ spec/_tmp/*/
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 1.9.3
5
+ addons:
6
+ code_climate:
7
+ repo_token: 1ba540ca1a06382432295a8c6afa3d6ffccda11fa9b43a429db604545a5c3ee4
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in marsdawn.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'coveralls', :require => false
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,119 @@
1
+ [![Build Status](https://travis-ci.org/nao58/marsdawn.svg?branch=master)](https://travis-ci.org/nao58/marsdawn)
2
+ [![Coverage Status](https://coveralls.io/repos/nao58/marsdawn/badge.png?branch=master)](https://coveralls.io/r/nao58/marsdawn?branch=master)
3
+ [![Code Climate](https://codeclimate.com/github/nao58/marsdawn.png)](https://codeclimate.com/github/nao58/marsdawn)
4
+
5
+ # Marsdawn
6
+
7
+ MarsDawn is simple static document builder and traverser. You can create your own document site easily using this gem.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'marsdawn'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install marsdawn
22
+
23
+ ## Usage
24
+
25
+ ### Create your document source
26
+
27
+ Use marsdawn command.
28
+
29
+ ~~~
30
+ marsdawn create "My Document"
31
+ ~~~
32
+
33
+ Then the document and files will be created like below.
34
+
35
+ ~~~
36
+ └── my_document
37
+ ├── .marsdawn.yml
38
+ └── .index.md
39
+ ~~~
40
+
41
+ The file `.marsdawn.yml` includes the information of whole document set. `.index.md` is the top page. You can edit the file to add your content.
42
+
43
+ To create new page.
44
+
45
+ ~~~
46
+ marsdawn page "About the document"
47
+ ~~~
48
+
49
+ ~~~
50
+ └── my_document
51
+ ├── .marsdawn.yml
52
+ ├── .index.md
53
+ └── 010_about-the-document.md
54
+ ~~~
55
+
56
+ To create new directory.
57
+
58
+ ~~~
59
+ marsdawn dir "Tutorial"
60
+ ~~~
61
+
62
+ ~~~
63
+ └── my_document
64
+ ├── .marsdawn.yml
65
+ ├── .index.md
66
+ ├── 010_about-the-document.md
67
+ └── 020_tutorial
68
+ └── .index.md
69
+ ~~~
70
+
71
+ ### Build the documents
72
+
73
+ Setting config file is the easiest way to build the document.
74
+
75
+ Create config file names "marsdawn.yml" under "config" directory of your framework.
76
+
77
+ ~~~config/marsdawn.yml
78
+ your_document_key:
79
+ source: path/to/your/source/documents
80
+ storage:
81
+ path: path/to/build/directory
82
+ ~~~
83
+
84
+ This time we will build the document onto the file system. You can choose RDBMS storage instead.
85
+
86
+ Then simply hit the rake command.
87
+
88
+ ~~~
89
+ rake marsdawn:build
90
+ ~~~
91
+
92
+ ### Traverse the documents
93
+
94
+ Once you have built the document, you can traverse the document easily from your own site.
95
+
96
+ This is a sample controller for Padrino.
97
+
98
+ ~~~ruby
99
+ YourWeb::App.controllers :docs do
100
+
101
+ get :index, :map => '/docs/*path' do
102
+ docset = Marsdawn::Site.new(key: 'your_document_key', lang: 'en', version: '1.0.0', base_path: '/docs')
103
+ @page = docset.page("/#{params[:path].join('/')}")
104
+ @title = @page.title
105
+ render 'docs'
106
+ end
107
+
108
+ end
109
+ ~~~
110
+
111
+ Now you can create your templete for the document page.
112
+
113
+ ## Contributing
114
+
115
+ 1. Fork it ( http://github.com/nao58/marsdawn/fork )
116
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
117
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
118
+ 4. Push to the branch (`git push origin my-new-feature`)
119
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => [:spec]
4
+ begin
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = 'spec/**/*_spec.rb'
8
+ spec.rspec_opts = ['-cfd']
9
+ end
10
+ rescue LoadError => e
11
+ p e
12
+ end
data/bin/marsdawn ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'marsdawn/command'
4
+
5
+ command = Marsdawn::Command.exec(ARGV)
6
+ exec command unless command.nil?
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ require "marsdawn/source"
4
+
5
+ class Marsdawn::Builder
6
+
7
+ def self.build config
8
+ raise "No specification for source path." unless config.key?(:source)
9
+ raise "No specification for storage config." unless config.key?(:storage)
10
+ source = Marsdawn::Source.new(config[:source])
11
+ storage = Marsdawn::Storage.get(config[:storage], source.doc_info)
12
+ build_source source, storage, config[:build_options]
13
+ create_search_index storage, config[:search] if config.key?(:search)
14
+ end
15
+
16
+ def self.build_source source, storage, options
17
+ options ||= {}
18
+ kramdown_options = options[:kramdown] || {}
19
+ storage.prepare
20
+ storage.set_document_info source.doc_info
21
+ source.each_contents(kramdown_options) do |uri, content, front_matter, sysinfo|
22
+ storage.set uri, content, front_matter, sysinfo
23
+ end
24
+ storage.finalize
25
+ rescue => ex
26
+ storage.clean_up
27
+ raise ex
28
+ end
29
+
30
+ def self.create_search_index storage, options
31
+ options ||= {}
32
+ Marsdawn::Search.create_index storage, options
33
+ end
34
+
35
+ end
@@ -0,0 +1,154 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ module Marsdawn
6
+ class Command
7
+ attr_accessor :editor, :auto_editor
8
+
9
+ class ParamError < Exception; end
10
+ class RuntimeError < Exception; end
11
+
12
+ def self.exec argv
13
+ raise ParamError.new("No command is specified.") if argv.empty?
14
+ cmd = new
15
+ command = argv.shift.to_sym
16
+ raise ParamError.new("Unknown command '#{command}'.") unless cmd.respond_to?(command)
17
+ value = (argv.size > 0 ? argv.shift : nil)
18
+ opts = parse_options(argv)
19
+ cmd.__send__ command, value, opts
20
+ end
21
+
22
+ def initialize
23
+ @editor = 'vim'
24
+ @auto_editor = true
25
+ read_dot_marsdawn
26
+ end
27
+
28
+ def create title, opts={}
29
+ key = (opts.key?(:file) ? opts[:file] : file_namize(title))
30
+ path = File.expand_path(key)
31
+ raise "The directory '#{doc_name}' already exists." if File.exists?(path)
32
+ Dir.mkdir path
33
+ data = {key: key, title: title, lang: 'en', version: '0.0.1'}
34
+ dot_file = File.join(path, '.marsdawn.yml')
35
+ index_file = File.join(path, '.index.md')
36
+ File.write dot_file, YAML.dump(data)
37
+ create_page index_file, title, 'title' => title
38
+ edit_cmd dot_file, index_file if @auto_editor || opts[:edit]
39
+ end
40
+
41
+ def dir title, opts={}
42
+ dir = (opts.key?(:file) ? opts[:file] : file_namize(title))
43
+ dir = add_num(dir, opts)
44
+ path = File.expand_path(dir)
45
+ Dir.mkdir path
46
+ index_file = File.join(path, '.index.md')
47
+ create_page index_file, title, 'title' => title
48
+ edit_cmd index_file if @auto_editor || opts[:edit]
49
+ end
50
+
51
+ def page title, opts={}
52
+ file = (opts.key?(:file) ? "#{opts[:file]}.md" : file_namize(title, '.md'))
53
+ file = File.expand_path(add_num(file, opts))
54
+ create_page file, title, 'title' => title
55
+ edit_cmd file if @auto_editor || opts[:edit]
56
+ end
57
+
58
+ def renum step, opts={}
59
+ step = (step.nil? ? 10 : step.to_i)
60
+ num = 0
61
+ list = Dir.glob('*').sort.each_with_object({}) do |item, ret|
62
+ num += step
63
+ ret[item] = add_num(item, num: num, step: step)
64
+ end
65
+ list.each do |src, dest|
66
+ FileUtils.mv src, dest unless src == dest
67
+ end
68
+ 'ls -1'
69
+ end
70
+
71
+ def debug type, opts={}
72
+ case type
73
+ when 'options'
74
+ opts
75
+ end
76
+ end
77
+
78
+ private
79
+ def self.parse_options argv
80
+ opts = {}
81
+ while argv.size > 0 do
82
+ key = opt_key(argv.shift)
83
+ val = true
84
+ val = argv.shift if argv.size > 0 && !argv.first.start_with?('-')
85
+ opts[key] = val
86
+ end
87
+ opts
88
+ end
89
+
90
+ def self.opt_key switch
91
+ opt_keys = {
92
+ 'e' => 'edit',
93
+ 'f' => 'file',
94
+ 'n' => 'num',
95
+ 'o' => 'no-num',
96
+ 's' => 'step'
97
+ }
98
+ key = switch
99
+ if key =~ /^--(.+)$/
100
+ key = $1
101
+ elsif key =~ /^-(.+)$/
102
+ key = opt_keys[$1]
103
+ end
104
+ raise ParamError.new("Unknown option '#{switch}'.") unless opt_keys.values.include?(key)
105
+ key.to_sym
106
+ end
107
+
108
+ def read_dot_marsdawn
109
+ dotfile = File.expand_path("#{ENV['HOME']}/.marsdawn")
110
+ instance_eval(open(dotfile).read) if File.exists?(dotfile)
111
+ end
112
+
113
+ def file_namize title, ext=''
114
+ "#{title.downcase.gsub(' ', '-')}#{ext}"
115
+ end
116
+
117
+ def create_page path, title, front_matter={}
118
+ File.write(path, "#{YAML.dump(front_matter)}---\n\n# #{title}\n\n")
119
+ end
120
+
121
+ def file_num file
122
+ file =~ /^(\d+)_(.+)$/ ? $1.to_i : 0
123
+ end
124
+
125
+ def file_name file
126
+ file =~ /^(\d+)_(.+)$/ ? $2 : file
127
+ end
128
+
129
+
130
+ def step opts
131
+ opts.key?(:step) ? opts[:step] : 10
132
+ end
133
+
134
+ def add_num file, opts
135
+ if opts.key?(:num)
136
+ num = opts[:num]
137
+ num = max_num + step(opts) if num.is_a?(TrueClass)
138
+ num = "000#{num}".slice(-3, 3)
139
+ file = "#{num}_#{file_name(file)}"
140
+ end
141
+ file
142
+ end
143
+
144
+ def max_num
145
+ list = Dir.glob('*')
146
+ list.size > 0 ? list.map{|item| file_num(item)}.max : 0
147
+ end
148
+
149
+ def edit_cmd *args
150
+ "#{@editor} #{args.join(" ")}"
151
+ end
152
+
153
+ end
154
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ class Marsdawn::Config
4
+
5
+ def initialize file='./config/marsdawn.yml'
6
+ file = File.absolute_path(file)
7
+ raise "Cannot find a config file for marsdawn." unless File.exists?(file)
8
+ @config = YAML.load_file(file)
9
+ end
10
+
11
+ def get key, entry, default=nil
12
+ conf = to_hash(key)
13
+ conf[entry] = default if !default.nil? && !conf.key?(entry)
14
+ raise "No entry '#{entry}' in the setting file of marsdawn." unless conf.key?(entry)
15
+ ret = conf[entry]
16
+ ret = Marsdawn::Util.hash_symbolize_keys(ret) if ret.kind_of?(Hash)
17
+ ret
18
+ end
19
+
20
+ def to_hash key
21
+ raise "Cannot find the configuration for '#{key}' in marsdawn.yml." unless @config.key?(key)
22
+ Marsdawn::Util.hash_symbolize_keys(@config[key])
23
+ end
24
+
25
+ def each
26
+ @config.keys.each do |key|
27
+ yield key, to_hash(key)
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+
3
+ class Marsdawn::Search::Rroonga
4
+
5
+ def initialize opts, storage
6
+ unless Module.const_defined?('Groonga')
7
+ raise "Gem 'rroonga' should be installed." unless require 'groonga'
8
+ end
9
+ raise "The groonga database path should be specified" unless opts.key?(:path)
10
+ @opts = {
11
+ index_table: {}
12
+ }.merge(opts)
13
+ @storage = storage
14
+ Groonga::Database.open(opts[:path])
15
+ @table_prefix = "#{@storage.key}-#{@storage.lang}-#{@storage.version.tr('.','_')}"
16
+ end
17
+
18
+ def create_tables
19
+ index_table = {
20
+ :type => :patricia_trie,
21
+ :normalizer => :NormalizerAuto,
22
+ :default_tokenizer => 'TokenBigram'
23
+ }.merge(@opts[:index_table])
24
+ Groonga::Schema.create_table(table_name('documents'), :type => :hash) do |tbl|
25
+ tbl.text('title')
26
+ tbl.text('content')
27
+ end
28
+ Groonga::Schema.create_table(table_name('terms'), index_table) do |tbl|
29
+ tbl.index(col_name('documents', 'title'))
30
+ tbl.index(col_name('documents', 'content'))
31
+ end
32
+ end
33
+
34
+ def drop_tables
35
+ Groonga::Schema.remove_table(table_name('documents'))
36
+ Groonga::Schema.remove_table(table_name('terms'))
37
+ rescue Groonga::Schema::TableNotExists
38
+ end
39
+
40
+ def create_index
41
+ drop_tables
42
+ create_tables
43
+ docs = table('documents')
44
+ index = @storage.get_document_info[:site_index]
45
+ index.each do |uri, title|
46
+ page = @storage.get(uri)
47
+ docs.add(uri, :title => title, :content => Marsdawn::Util.strip_tags(page[:content]))
48
+ end
49
+ end
50
+
51
+ def search keyword, opts={}
52
+ snippet = Groonga::Snippet.new(html_escape: true, default_open_tag: '<strong>', default_close_tag: '</strong>', normalize: true)
53
+ words = keyword.scan(/(?:\w|"[^"]*")+/).map{|w| w.delete('"')}
54
+ words.each{|word| snippet.add_keyword(word, opts)}
55
+ docs = table('documents')
56
+ docs.select do |rec|
57
+ expression = nil
58
+ words.each do |word|
59
+ sub_exp = (rec.content =~ word)
60
+ if expression.nil?
61
+ expression = sub_exp
62
+ else
63
+ expression &= sub_exp
64
+ end
65
+ end
66
+ expression
67
+ end.map{|rec| {uri: rec.key.key, title: rec.title, results: snippet.execute(rec.content)}}
68
+ end
69
+
70
+ private
71
+ def table_name name
72
+ "#{@table_prefix}-#{name}"
73
+ end
74
+
75
+ def table name
76
+ Groonga[table_name(name)]
77
+ end
78
+
79
+ def col_name table, column
80
+ "#{table_name(table)}.#{column}"
81
+ end
82
+
83
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ class Marsdawn::Search
4
+
5
+ def self.create_index storage, opts
6
+ self.get(storage, opts).create_index
7
+ end
8
+
9
+ def self.get storage, opts
10
+ opts = Marsdawn::Util.hash_symbolize_keys(opts)
11
+ key = opts[:type]
12
+ @@base_path ||= File.join(File.dirname(__FILE__), 'search')
13
+ Marsdawn::Util.adapter(self, class_name, @@base_path).new config, opts
14
+ end
15
+
16
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ class Marsdawn::Site
4
+ class Breadcrumb < Hash
5
+
6
+ def initialize site, crumb
7
+ @site = site
8
+ crumb.each do |path|
9
+ self[path] = Marsdawn::Site::Link.new(@site, path)
10
+ end
11
+ end
12
+
13
+ def to_s
14
+ to_html
15
+ end
16
+
17
+ def to_html
18
+ words = []
19
+ if self.size > 0
20
+ words << '<ul>'
21
+ self.each do |uri, link|
22
+ words << "<li>#{link.to_html}</li>"
23
+ end
24
+ words << '</ul>'
25
+ end
26
+ words.join('')
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+
3
+ class Marsdawn::Site
4
+ class Indexer < Hash
5
+
6
+ def initialize site, index={}
7
+ @site = site
8
+ @current_page = nil
9
+ index.each do |uri, title|
10
+ self[uri] = Marsdawn::Site::Link.new(@site, uri, title)
11
+ end
12
+ end
13
+
14
+ def current_page path
15
+ @current_page = path
16
+ self
17
+ end
18
+
19
+ #def parent path
20
+ # parent_path = "#{File.dirname(path)}/"
21
+ # self.each_with_object(Marsdawn::Site::Indexer.new(@site).current_page(path)) do |(uri, link), ret|
22
+ # ret[uri] = link if uri == parent_path
23
+ # end
24
+ #end
25
+
26
+ def under path
27
+ base = path + (path == '/' ? '' : '/')
28
+ self.each_with_object(Marsdawn::Site::Indexer.new(@site).current_page(path)) do |(uri, link), ret|
29
+ ret[uri] = link if uri.start_with?(base) && uri != base
30
+ end
31
+ end
32
+
33
+ def neighbor path
34
+ level = path.count('/')
35
+ base = File.dirname(path)
36
+ base = "#{base}/" if base != '/'
37
+ self.each_with_object(Marsdawn::Site::Indexer.new(@site).current_page(path)) do |(uri, link), ret|
38
+ ret[uri] = link if uri.start_with?(base) && uri.count('/') == level && uri != base
39
+ end
40
+ end
41
+
42
+ def to_s
43
+ to_html
44
+ end
45
+
46
+ def to_html options={}
47
+ if self.size > 0
48
+ opts = {
49
+ }.merge(options)
50
+ create_link_html File.dirname(self.keys.first), opts
51
+ else
52
+ ""
53
+ end
54
+ end
55
+
56
+ private
57
+ def create_link_html path, opts={}
58
+ base_level = path.count('/')
59
+ words = []
60
+ words << '<ul>'
61
+ self.each do |uri, link|
62
+ next unless uri.start_with?(path)
63
+ level = uri.count('/')
64
+ if base_level < level
65
+ words.insert -2, create_link_html(uri)
66
+ elsif base_level == level
67
+ attr = (uri == @current_page ? ' class="current-page"' : '')
68
+ words << "<li#{attr}>"
69
+ words << link.to_html
70
+ words << '</li>'
71
+ end
72
+ end
73
+ words << '</ul>'
74
+ words.size > 2 ? words.join('') : ""
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ class Marsdawn::Site
4
+ class Link
5
+ attr_reader :uri, :title, :site, :full_path
6
+
7
+ def initialize site, uri, title=nil
8
+ @uri = uri
9
+ @title = (title.nil? ? site.page_title(uri) : title)
10
+ @site = site
11
+ @full_path = @site.full_path(@uri)
12
+ end
13
+
14
+ def page
15
+ @site.page @uri
16
+ end
17
+
18
+ def to_s
19
+ to_html
20
+ end
21
+
22
+ def to_html
23
+ t = CGI.escapeHTML(@title)
24
+ %!<a href="#{@full_path}" title="#{t}">#{t}</a>!
25
+ end
26
+
27
+ end
28
+ end