hx 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/VERSION +1 -1
- data/lib/hx.rb +9 -269
- data/lib/hx/backend/hobix.rb +92 -0
- data/lib/hx/commandline.rb +2 -2
- data/lib/hx/listing/limit.rb +53 -0
- data/lib/hx/listing/paginate.rb +77 -0
- data/lib/hx/listing/recursiveindex.rb +73 -0
- data/lib/hx/output/liquidtemplate.rb +101 -0
- metadata +6 -1
data/LICENSE
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.3
|
data/lib/hx.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# hx - A very small website generator.
|
2
2
|
#
|
3
|
-
# Copyright (c) 2009 MenTaLguY <mental@rydia.net>
|
3
|
+
# Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net>
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining
|
6
6
|
# a copy of this software and associated documentation files (the
|
@@ -21,17 +21,10 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'cgi'
|
25
24
|
require 'rubygems'
|
26
|
-
require 'ostruct'
|
27
25
|
require 'set'
|
28
|
-
require 'date'
|
29
|
-
require 'time'
|
30
|
-
require 'fileutils'
|
31
26
|
require 'pathname'
|
32
27
|
require 'yaml'
|
33
|
-
require 'liquid'
|
34
|
-
require 'redcloth'
|
35
28
|
|
36
29
|
module Hx
|
37
30
|
|
@@ -126,17 +119,6 @@ class Overlay
|
|
126
119
|
@sources = sources
|
127
120
|
end
|
128
121
|
|
129
|
-
def edit_entry(path, prototype=nil)
|
130
|
-
@sources.each do |source|
|
131
|
-
begin
|
132
|
-
source.edit_entry(path, prototype) { |text| yield text }
|
133
|
-
break
|
134
|
-
rescue EditingNotSupportedError
|
135
|
-
end
|
136
|
-
end
|
137
|
-
self
|
138
|
-
end
|
139
|
-
|
140
122
|
def each_entry
|
141
123
|
seen = Set[]
|
142
124
|
@sources.each do |source|
|
@@ -222,10 +204,11 @@ class Cache
|
|
222
204
|
|
223
205
|
def each_entry
|
224
206
|
unless @entries
|
225
|
-
|
207
|
+
entries = []
|
226
208
|
@source.each_entry do |path, entry|
|
227
|
-
|
209
|
+
entries << [path, entry]
|
228
210
|
end
|
211
|
+
@entries = entries
|
229
212
|
end
|
230
213
|
@entries.each do |path, entry|
|
231
214
|
yield path, entry.dup
|
@@ -489,261 +472,18 @@ end
|
|
489
472
|
|
490
473
|
class FileBuilder
|
491
474
|
def initialize(output_dir)
|
492
|
-
@output_dir = output_dir
|
475
|
+
@output_dir = Pathname.new(output_dir)
|
493
476
|
end
|
494
477
|
|
495
478
|
def build_file(path, entry)
|
496
|
-
filename =
|
497
|
-
dirname =
|
498
|
-
|
499
|
-
|
479
|
+
filename = @output_dir + path
|
480
|
+
dirname = filename.parent
|
481
|
+
dirname.mkpath()
|
482
|
+
filename.open("wb") do |stream|
|
500
483
|
stream.write entry['content'].to_s
|
501
484
|
end
|
502
|
-
end
|
503
|
-
end
|
504
|
-
|
505
|
-
module Backend
|
506
|
-
|
507
|
-
class Hobix
|
508
|
-
include Source
|
509
|
-
|
510
|
-
def initialize(source, options)
|
511
|
-
@entry_dir = Hx.get_pathname(options, :entry_dir)
|
512
|
-
end
|
513
|
-
|
514
|
-
def yaml_repr(value)
|
515
|
-
YAML.parse(YAML.dump(value))
|
516
|
-
end
|
517
|
-
private :yaml_repr
|
518
|
-
|
519
|
-
def edit_entry(path, prototype=nil)
|
520
|
-
entry_filename = @entry_dir + "#{path}.yaml"
|
521
|
-
begin
|
522
|
-
text = entry_filename.read
|
523
|
-
previous_mtime = entry_filename.mtime
|
524
|
-
rescue Errno::ENOENT
|
525
|
-
raise NoSuchEntryError, path unless prototype
|
526
|
-
prototype = prototype.dup
|
527
|
-
prototype['content'] = (prototype['content'] || "").dup
|
528
|
-
content = prototype['content']
|
529
|
-
def content.to_yaml_style ; :literal ; end
|
530
|
-
native = YAML::DomainType.new('hobix.com,2004', 'entry', prototype)
|
531
|
-
text = YAML.dump(native)
|
532
|
-
previous_mtime = nil
|
533
|
-
end
|
534
|
-
text = yield text
|
535
|
-
repr = YAML.parse(text)
|
536
|
-
keys = {}
|
537
|
-
repr.value.each_key { |key| keys[key.value] = key }
|
538
|
-
%w(created updated).each { |name| keys[name] ||= yaml_repr(name) }
|
539
|
-
update_time = Time.now
|
540
|
-
update_time_repr = yaml_repr(update_time)
|
541
|
-
previous_mtime ||= update_time
|
542
|
-
previous_mtime_repr = yaml_repr(previous_mtime)
|
543
|
-
repr.add(keys['created'], previous_mtime_repr) unless repr['created']
|
544
|
-
repr.add(keys['updated'], update_time_repr)
|
545
|
-
entry_filename.parent.mkpath()
|
546
|
-
entry_filename.open('w') { |stream| stream << repr.emit }
|
547
|
-
self
|
548
|
-
end
|
549
|
-
|
550
|
-
def each_entry
|
551
|
-
Pathname.glob(@entry_dir + '**/*.yaml') do |entry_filename|
|
552
|
-
path = entry_filename.relative_path_from(@entry_dir).to_s
|
553
|
-
path.sub!(/\.yaml$/, '')
|
554
|
-
entry = entry_filename.open('r') do |stream|
|
555
|
-
YAML.load(stream).value
|
556
|
-
end
|
557
|
-
entry['updated'] ||= entry_filename.mtime
|
558
|
-
entry['created'] ||= entry['updated']
|
559
|
-
yield path, entry
|
560
|
-
end
|
561
|
-
self
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
end
|
566
|
-
|
567
|
-
module Listing
|
568
|
-
|
569
|
-
class RecursiveIndex
|
570
|
-
include Source
|
571
|
-
|
572
|
-
def self.new(source, options)
|
573
|
-
listing = super(source, options)
|
574
|
-
if options.has_key? :limit
|
575
|
-
listing = Limit.new(listing, :limit => options[:limit])
|
576
|
-
end
|
577
|
-
if options.has_key? :page_size
|
578
|
-
listing = Paginate.new(listing, :page_size => options[:page_size])
|
579
|
-
end
|
580
|
-
listing
|
581
|
-
end
|
582
|
-
|
583
|
-
def initialize(source, options)
|
584
|
-
@source = source
|
585
|
-
end
|
586
|
-
|
587
|
-
def each_entry
|
588
|
-
indexes = Hash.new { |h,k| h[k] = {'items' => []} }
|
589
|
-
@source.each_entry do |path, entry|
|
590
|
-
components = path.split("/")
|
591
|
-
until components.empty?
|
592
|
-
components.pop
|
593
|
-
index_path = (components + ["index"]).join("/")
|
594
|
-
index = indexes[index_path]
|
595
|
-
index['items'] << {'path' => path, 'entry' => entry}
|
596
|
-
if entry['modified'] and
|
597
|
-
(not index['modified'] or entry['modified'] > index['modified'])
|
598
|
-
index['modified'] = entry['modified']
|
599
|
-
end
|
600
|
-
end
|
601
|
-
end
|
602
|
-
indexes.each do |path, entry|
|
603
|
-
yield path, entry
|
604
|
-
end
|
605
485
|
self
|
606
486
|
end
|
607
487
|
end
|
608
488
|
|
609
|
-
class Paginate
|
610
|
-
include Source
|
611
|
-
|
612
|
-
def initialize(source, options)
|
613
|
-
@source = source
|
614
|
-
@page_size = options[:page_size]
|
615
|
-
end
|
616
|
-
|
617
|
-
def each_entry
|
618
|
-
@source.each_entry do |index_path, index_entry|
|
619
|
-
items = index_entry['items'] || []
|
620
|
-
if items.empty?
|
621
|
-
index_entry = index_entry.dup
|
622
|
-
index_entry['pages'] = [index_entry]
|
623
|
-
index_entry['page_index'] = 0
|
624
|
-
yield index_path, index_entry
|
625
|
-
else
|
626
|
-
pages = []
|
627
|
-
n_pages = (items.size + @page_size - 1) / @page_size
|
628
|
-
for num in 0...n_pages
|
629
|
-
page_items = items[@page_size * num, @page_size]
|
630
|
-
entry = index_entry.dup
|
631
|
-
entry['items'] = page_items
|
632
|
-
entry['prev_page'] = "#{num}"
|
633
|
-
entry['next_page'] = "#{num+2}"
|
634
|
-
entry['pages'] = pages
|
635
|
-
entry['page_index'] = num
|
636
|
-
pages << {'path' => "#{index_path}/#{num+1}", 'entry' => entry}
|
637
|
-
end
|
638
|
-
pages[0]['path'] = index_path
|
639
|
-
pages[0]['entry'].delete('prev_page')
|
640
|
-
if pages.size > 1
|
641
|
-
index_name = index_path.split('/').last
|
642
|
-
pages[0]['entry']['next_page'] = "#{index_name}/2"
|
643
|
-
pages[1]['entry']['prev_page'] = "../#{index_name}"
|
644
|
-
end
|
645
|
-
pages[-1]['entry'].delete('next_page')
|
646
|
-
pages.each do |page|
|
647
|
-
yield page['path'], page['entry']
|
648
|
-
end
|
649
|
-
end
|
650
|
-
end
|
651
|
-
self
|
652
|
-
end
|
653
|
-
end
|
654
|
-
|
655
|
-
class Limit
|
656
|
-
include Source
|
657
|
-
|
658
|
-
def initialize(source, options)
|
659
|
-
@source = source
|
660
|
-
@limit = options[:limit]
|
661
|
-
end
|
662
|
-
|
663
|
-
def each_entry
|
664
|
-
@source.each_entry do |path, entry|
|
665
|
-
if entry['items']
|
666
|
-
trimmed_entry = entry.dup
|
667
|
-
trimmed_entry['items'] = entry['items'][0...@limit]
|
668
|
-
else
|
669
|
-
trimmed_entry = entry
|
670
|
-
end
|
671
|
-
yield path, trimmed_entry
|
672
|
-
end
|
673
|
-
self
|
674
|
-
end
|
675
|
-
end
|
676
|
-
|
677
|
-
end
|
678
|
-
|
679
|
-
module Output
|
680
|
-
|
681
|
-
class LiquidTemplate
|
682
|
-
include Source
|
683
|
-
|
684
|
-
module TextFilters
|
685
|
-
def textilize(input)
|
686
|
-
RedCloth.new(input).to_html
|
687
|
-
end
|
688
|
-
|
689
|
-
def escape_url(input)
|
690
|
-
CGI.escape(input)
|
691
|
-
end
|
692
|
-
|
693
|
-
def escape_xml(input)
|
694
|
-
CGI.escapeHTML(input)
|
695
|
-
end
|
696
|
-
|
697
|
-
def path_to_url(input, base_url)
|
698
|
-
"#{base_url}#{input}"
|
699
|
-
end
|
700
|
-
|
701
|
-
def handleize(input)
|
702
|
-
"id_#{input.to_s.gsub(/[^A-Za-z0-9]/, '_')}"
|
703
|
-
end
|
704
|
-
|
705
|
-
def xsd_datetime(input)
|
706
|
-
input = Time.parse(input) unless Time === input
|
707
|
-
input.xmlschema
|
708
|
-
end
|
709
|
-
end
|
710
|
-
|
711
|
-
def initialize(source, options)
|
712
|
-
@source = source
|
713
|
-
@options = {}
|
714
|
-
for key, value in options
|
715
|
-
@options[key.to_s] = value
|
716
|
-
end
|
717
|
-
template_dir = Hx.get_pathname(options, :template_dir)
|
718
|
-
# global, so all LiquidTemplate instances kind of have to agree on the
|
719
|
-
# same template directory for things to work right
|
720
|
-
Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_dir)
|
721
|
-
Liquid::Template.register_filter(TextFilters)
|
722
|
-
template_file = template_dir + options[:template]
|
723
|
-
@template = template_file.open('r') { |s| Liquid::Template.parse(s.read) }
|
724
|
-
@extension = options[:extension]
|
725
|
-
end
|
726
|
-
|
727
|
-
def each_entry
|
728
|
-
@source.each_entry do |path, entry|
|
729
|
-
unless @extension.nil?
|
730
|
-
output_path = "#{path}.#{@extension}"
|
731
|
-
else
|
732
|
-
output_path = path
|
733
|
-
end
|
734
|
-
output_entry = entry.dup
|
735
|
-
output_entry['content'] = @template.render(
|
736
|
-
'now' => Time.now,
|
737
|
-
'options' => @options,
|
738
|
-
'path' => path,
|
739
|
-
'entry' => entry
|
740
|
-
)
|
741
|
-
yield output_path, output_entry
|
742
|
-
end
|
743
|
-
self
|
744
|
-
end
|
745
|
-
end
|
746
|
-
|
747
|
-
end
|
748
|
-
|
749
489
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# hx/backend/hobix - Hobix filesystem backend for Hx
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net>
|
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.
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'time'
|
26
|
+
require 'pathname'
|
27
|
+
require 'yaml'
|
28
|
+
require 'hx'
|
29
|
+
|
30
|
+
module Hx
|
31
|
+
module Backend
|
32
|
+
|
33
|
+
class Hobix
|
34
|
+
include Hx::Source
|
35
|
+
|
36
|
+
def initialize(source, options)
|
37
|
+
@entry_dir = Hx.get_pathname(options, :entry_dir)
|
38
|
+
end
|
39
|
+
|
40
|
+
def yaml_repr(value)
|
41
|
+
YAML.parse(YAML.dump(value))
|
42
|
+
end
|
43
|
+
private :yaml_repr
|
44
|
+
|
45
|
+
def edit_entry(path, prototype=nil)
|
46
|
+
entry_filename = @entry_dir + "#{path}.yaml"
|
47
|
+
begin
|
48
|
+
text = entry_filename.read
|
49
|
+
previous_mtime = entry_filename.mtime
|
50
|
+
rescue Errno::ENOENT
|
51
|
+
raise NoSuchEntryError, path unless prototype
|
52
|
+
prototype = prototype.dup
|
53
|
+
prototype['content'] = (prototype['content'] || "").dup
|
54
|
+
content = prototype['content']
|
55
|
+
def content.to_yaml_style ; :literal ; end
|
56
|
+
native = YAML::DomainType.new('hobix.com,2004', 'entry', prototype)
|
57
|
+
text = YAML.dump(native)
|
58
|
+
previous_mtime = nil
|
59
|
+
end
|
60
|
+
text = yield text
|
61
|
+
repr = YAML.parse(text)
|
62
|
+
keys = {}
|
63
|
+
repr.value.each_key { |key| keys[key.value] = key }
|
64
|
+
%w(created updated).each { |name| keys[name] ||= yaml_repr(name) }
|
65
|
+
update_time = Time.now
|
66
|
+
update_time_repr = yaml_repr(update_time)
|
67
|
+
previous_mtime ||= update_time
|
68
|
+
previous_mtime_repr = yaml_repr(previous_mtime)
|
69
|
+
repr.add(keys['created'], previous_mtime_repr) unless repr['created']
|
70
|
+
repr.add(keys['updated'], update_time_repr)
|
71
|
+
entry_filename.parent.mkpath()
|
72
|
+
entry_filename.open('w') { |stream| stream << repr.emit }
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def each_entry
|
77
|
+
Pathname.glob(@entry_dir + '**/*.yaml') do |entry_filename|
|
78
|
+
path = entry_filename.relative_path_from(@entry_dir).to_s
|
79
|
+
path.sub!(/\.yaml$/, '')
|
80
|
+
entry = entry_filename.open('r') do |stream|
|
81
|
+
YAML.load(stream).value
|
82
|
+
end
|
83
|
+
entry['updated'] ||= entry_filename.mtime
|
84
|
+
entry['created'] ||= entry['updated']
|
85
|
+
yield path, entry
|
86
|
+
end
|
87
|
+
self
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
data/lib/hx/commandline.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# hx/commandline -
|
1
|
+
# hx/commandline - Commandline interface for Hx
|
2
2
|
#
|
3
|
-
# Copyright (c) 2009 MenTaLguY <mental@rydia.net>
|
3
|
+
# Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net>
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining
|
6
6
|
# a copy of this software and associated documentation files (the
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# hx/listing/limit - Listing length limiter
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net>
|
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.
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'hx'
|
26
|
+
|
27
|
+
module Hx
|
28
|
+
module Listing
|
29
|
+
|
30
|
+
class Limit
|
31
|
+
include Hx::Source
|
32
|
+
|
33
|
+
def initialize(source, options)
|
34
|
+
@source = source
|
35
|
+
@limit = options[:limit]
|
36
|
+
end
|
37
|
+
|
38
|
+
def each_entry
|
39
|
+
@source.each_entry do |path, entry|
|
40
|
+
if entry['items']
|
41
|
+
trimmed_entry = entry.dup
|
42
|
+
trimmed_entry['items'] = entry['items'][0...@limit]
|
43
|
+
else
|
44
|
+
trimmed_entry = entry
|
45
|
+
end
|
46
|
+
yield path, trimmed_entry
|
47
|
+
end
|
48
|
+
self
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# hx/listing/paginate - Listing paginator
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net>
|
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.
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'hx'
|
26
|
+
|
27
|
+
module Hx
|
28
|
+
module Listing
|
29
|
+
|
30
|
+
class Paginate
|
31
|
+
include Hx::Source
|
32
|
+
|
33
|
+
def initialize(source, options)
|
34
|
+
@source = source
|
35
|
+
@page_size = options[:page_size]
|
36
|
+
end
|
37
|
+
|
38
|
+
def each_entry
|
39
|
+
@source.each_entry do |index_path, index_entry|
|
40
|
+
items = index_entry['items'] || []
|
41
|
+
if items.empty?
|
42
|
+
index_entry = index_entry.dup
|
43
|
+
index_entry['pages'] = [index_entry]
|
44
|
+
index_entry['page_index'] = 0
|
45
|
+
yield index_path, index_entry
|
46
|
+
else
|
47
|
+
pages = []
|
48
|
+
n_pages = (items.size + @page_size - 1) / @page_size
|
49
|
+
for num in 0...n_pages
|
50
|
+
page_items = items[@page_size * num, @page_size]
|
51
|
+
entry = index_entry.dup
|
52
|
+
entry['items'] = page_items
|
53
|
+
entry['prev_page'] = "#{num}"
|
54
|
+
entry['next_page'] = "#{num+2}"
|
55
|
+
entry['pages'] = pages
|
56
|
+
entry['page_index'] = num
|
57
|
+
pages << {'path' => "#{index_path}/#{num+1}", 'entry' => entry}
|
58
|
+
end
|
59
|
+
pages[0]['path'] = index_path
|
60
|
+
pages[0]['entry'].delete('prev_page')
|
61
|
+
if pages.size > 1
|
62
|
+
index_name = index_path.split('/').last
|
63
|
+
pages[0]['entry']['next_page'] = "#{index_name}/2"
|
64
|
+
pages[1]['entry']['prev_page'] = "../#{index_name}"
|
65
|
+
end
|
66
|
+
pages[-1]['entry'].delete('next_page')
|
67
|
+
pages.each do |page|
|
68
|
+
yield page['path'], page['entry']
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
self
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# hx/listing/recursiveindex - Recursive index generator
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net>
|
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.
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'hx'
|
26
|
+
require 'hx/listing/limit'
|
27
|
+
require 'hx/listing/paginate'
|
28
|
+
|
29
|
+
module Hx
|
30
|
+
module Listing
|
31
|
+
|
32
|
+
class RecursiveIndex
|
33
|
+
include Hx::Source
|
34
|
+
|
35
|
+
def self.new(source, options)
|
36
|
+
listing = super(source, options)
|
37
|
+
if options.has_key? :limit
|
38
|
+
listing = Limit.new(listing, :limit => options[:limit])
|
39
|
+
end
|
40
|
+
if options.has_key? :page_size
|
41
|
+
listing = Paginate.new(listing, :page_size => options[:page_size])
|
42
|
+
end
|
43
|
+
listing
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(source, options)
|
47
|
+
@source = source
|
48
|
+
end
|
49
|
+
|
50
|
+
def each_entry
|
51
|
+
indexes = Hash.new { |h,k| h[k] = {'items' => []} }
|
52
|
+
@source.each_entry do |path, entry|
|
53
|
+
components = path.split("/")
|
54
|
+
until components.empty?
|
55
|
+
components.pop
|
56
|
+
index_path = (components + ["index"]).join("/")
|
57
|
+
index = indexes[index_path]
|
58
|
+
index['items'] << {'path' => path, 'entry' => entry}
|
59
|
+
if entry['modified'] and
|
60
|
+
(not index['modified'] or entry['modified'] > index['modified'])
|
61
|
+
index['modified'] = entry['modified']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
indexes.each do |path, entry|
|
66
|
+
yield path, entry
|
67
|
+
end
|
68
|
+
self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# hx/output/liquidtemplate - Liquid templates for Hx
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net>
|
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.
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'time'
|
26
|
+
require 'liquid'
|
27
|
+
require 'redcloth'
|
28
|
+
require 'cgi'
|
29
|
+
require 'hx'
|
30
|
+
|
31
|
+
module Hx
|
32
|
+
module Output
|
33
|
+
|
34
|
+
class LiquidTemplate
|
35
|
+
include Hx::Source
|
36
|
+
|
37
|
+
module TextFilters
|
38
|
+
def textilize(input)
|
39
|
+
RedCloth.new(input).to_html
|
40
|
+
end
|
41
|
+
|
42
|
+
def escape_url(input)
|
43
|
+
CGI.escape(input)
|
44
|
+
end
|
45
|
+
|
46
|
+
def escape_xml(input)
|
47
|
+
CGI.escapeHTML(input)
|
48
|
+
end
|
49
|
+
|
50
|
+
def path_to_url(input, base_url)
|
51
|
+
"#{base_url}#{input}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def handleize(input)
|
55
|
+
"id_#{input.to_s.gsub(/[^A-Za-z0-9]/, '_')}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def xsd_datetime(input)
|
59
|
+
input = Time.parse(input) unless Time === input
|
60
|
+
input.xmlschema
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(source, options)
|
65
|
+
@source = source
|
66
|
+
@options = {}
|
67
|
+
for key, value in options
|
68
|
+
@options[key.to_s] = value
|
69
|
+
end
|
70
|
+
template_dir = Hx.get_pathname(options, :template_dir)
|
71
|
+
# global, so all LiquidTemplate instances kind of have to agree on the
|
72
|
+
# same template directory for things to work right
|
73
|
+
Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_dir)
|
74
|
+
Liquid::Template.register_filter(TextFilters)
|
75
|
+
template_file = template_dir + options[:template]
|
76
|
+
@template = template_file.open('r') { |s| Liquid::Template.parse(s.read) }
|
77
|
+
@extension = options[:extension]
|
78
|
+
end
|
79
|
+
|
80
|
+
def each_entry
|
81
|
+
@source.each_entry do |path, entry|
|
82
|
+
unless @extension.nil?
|
83
|
+
output_path = "#{path}.#{@extension}"
|
84
|
+
else
|
85
|
+
output_path = path
|
86
|
+
end
|
87
|
+
output_entry = entry.dup
|
88
|
+
output_entry['content'] = @template.render(
|
89
|
+
'now' => Time.now,
|
90
|
+
'options' => @options,
|
91
|
+
'path' => path,
|
92
|
+
'entry' => entry
|
93
|
+
)
|
94
|
+
yield output_path, output_entry
|
95
|
+
end
|
96
|
+
self
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MenTaLguY
|
@@ -41,7 +41,12 @@ files:
|
|
41
41
|
- VERSION
|
42
42
|
- bin/hx
|
43
43
|
- lib/hx.rb
|
44
|
+
- lib/hx/backend/hobix.rb
|
44
45
|
- lib/hx/commandline.rb
|
46
|
+
- lib/hx/listing/limit.rb
|
47
|
+
- lib/hx/listing/paginate.rb
|
48
|
+
- lib/hx/listing/recursiveindex.rb
|
49
|
+
- lib/hx/output/liquidtemplate.rb
|
45
50
|
- spec/cache_spec.rb
|
46
51
|
- spec/hx_dummy.rb
|
47
52
|
- spec/hx_dummy2.rb
|