BxMS 0.0.18
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/bxms +8 -0
- data/bin/bxms.bat +3 -0
- data/bin/bxms.rb +8 -0
- data/bin/bxms.sh +3 -0
- data/examples/www.berlinfactor.com/Bx.css +317 -0
- data/examples/www.berlinfactor.com/Bx.js +39 -0
- data/examples/www.berlinfactor.com/Section.Books/books.txt +198 -0
- data/examples/www.berlinfactor.com/Section.Books/index.page +18 -0
- data/examples/www.berlinfactor.com/Section.Bx/index.page +18 -0
- data/examples/www.berlinfactor.com/Section.Contact/index.page +12 -0
- data/examples/www.berlinfactor.com/Section.Links/Game.Development.txt +6 -0
- data/examples/www.berlinfactor.com/Section.Links/News.and.Stuff.txt +10 -0
- data/examples/www.berlinfactor.com/Section.Links/Software.Development.txt +25 -0
- data/examples/www.berlinfactor.com/Section.Links/Symbian.Development.txt +22 -0
- data/examples/www.berlinfactor.com/Section.Links/Tools.and.Utilities.txt +15 -0
- data/examples/www.berlinfactor.com/Section.Links/index.page +31 -0
- data/examples/www.berlinfactor.com/favicon.ico +0 -0
- data/examples/www.berlinfactor.com/images/background.png +0 -0
- data/examples/www.berlinfactor.com/images/logo_above.gif +0 -0
- data/examples/www.berlinfactor.com/images/logo_below.gif +0 -0
- data/examples/www.berlinfactor.com/images/logo_clickable.gif +0 -0
- data/examples/www.berlinfactor.com/images/no_section_name.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_books.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_books_hover.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_books_name.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_bx.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_bx_hover.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_bx_name.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_contact.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_contact_hover.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_contact_name.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_links.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_links_hover.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_links_name.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_tfdj.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_tfdj_hover.gif +0 -0
- data/examples/www.berlinfactor.com/images/section_tfdj_name.gif +0 -0
- data/examples/www.berlinfactor.com/index.page +21 -0
- data/examples/www.berlinfactor.com/news.page +11 -0
- data/examples/www.berlinfactor.com/news.txt +210 -0
- data/src/bxms.rb +61 -0
- data/src/bxms/context.rb +96 -0
- data/src/bxms/functions.rb +39 -0
- data/src/bxms/processor.rb +53 -0
- data/src/bxms/root_state.rb +30 -0
- data/src/bxms/rules.rb +82 -0
- data/src/bxms/state.rb +105 -0
- data/src/bxms/tags.rb +108 -0
- data/src/bxms/variables.rb +9 -0
- data/src/page/part.rb +51 -0
- data/src/page/part_collector.rb +55 -0
- data/src/rules/base.rb +16 -0
- data/src/rules/copy.rb +17 -0
- data/src/rules/ignore.rb +14 -0
- data/src/rules/process.rb +23 -0
- data/src/rules/process_page.rb +69 -0
- data/src/util/chained_hash.rb +41 -0
- data/src/util/logger.rb +710 -0
- data/src/util/system_logger.rb +30 -0
- metadata +116 -0
data/src/bxms.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
require 'optparse'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
require 'bxms/processor'
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
options = OpenStruct.new
|
10
|
+
options.site_dir = nil
|
11
|
+
options.output_dir = 'output'
|
12
|
+
options.verbose = false
|
13
|
+
|
14
|
+
parser = OptionParser.new do |opts|
|
15
|
+
opts.banner = "Usage: #{$0} [options]"
|
16
|
+
|
17
|
+
opts.separator ""
|
18
|
+
|
19
|
+
opts.on( "-i", "--input=dir", String, "Directory containing the site data" ) do |val|
|
20
|
+
options.site_dir = val
|
21
|
+
end
|
22
|
+
opts.on( "-o", "--output=dir", String, "Directory where output should be placed" ) do |val|
|
23
|
+
options.output_dir = val
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on( "-v", "--verbose", "Run verbosely" ) do |val|
|
27
|
+
options.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
31
|
+
puts opts
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
parser.parse!( ARGV )
|
37
|
+
|
38
|
+
options.site_dir = ARGV.delete_at( 0 ) if !options.site_dir && ARGV.length > 0
|
39
|
+
options.output_dir = ARGV.delete_at( 0 ) if !options.output_dir && ARGV.length > 0
|
40
|
+
|
41
|
+
|
42
|
+
def normalize( filename )
|
43
|
+
filename.gsub '\\', '/' if filename
|
44
|
+
end
|
45
|
+
|
46
|
+
def fail( message )
|
47
|
+
puts "ERROR: #{message}"
|
48
|
+
exit 10
|
49
|
+
end
|
50
|
+
|
51
|
+
source = normalize options.site_dir
|
52
|
+
destination = normalize options.output_dir
|
53
|
+
|
54
|
+
fail "Missing input folder" unless source
|
55
|
+
fail "Not a valid input folder: #{source}" unless File.directory? source
|
56
|
+
|
57
|
+
destination = File.join( destination, File.basename( source ) )
|
58
|
+
|
59
|
+
bxms = BxMS::Processor.new
|
60
|
+
bxms.verbose = options.verbose
|
61
|
+
bxms.process :from => source, :to => destination
|
data/src/bxms/context.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
require 'util/system_logger'
|
3
|
+
|
4
|
+
module BxMS
|
5
|
+
|
6
|
+
class Context
|
7
|
+
|
8
|
+
def initialize( input_file, state )
|
9
|
+
@logger = Util::SystemLogger.new 'Context'
|
10
|
+
@input_file = input_file
|
11
|
+
@state = state
|
12
|
+
|
13
|
+
@variables = BxMS::Variables.new @state.variables
|
14
|
+
|
15
|
+
set_variable :input_file, @input_file
|
16
|
+
set_variable :context, self
|
17
|
+
|
18
|
+
define_methods
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_file( file_name )
|
22
|
+
local_file = state.get_local_file( file_name )
|
23
|
+
return IO.read( local_file ) if File.exists? local_file
|
24
|
+
|
25
|
+
root_file = state.get_root_file( file_name )
|
26
|
+
return IO.read( root_file ) if File.exists? root_file
|
27
|
+
|
28
|
+
raise "Unable to find #{file_name}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def run_erb_on( template, file_name )
|
32
|
+
body = template
|
33
|
+
loop do
|
34
|
+
new_body = erbify body, file_name
|
35
|
+
break if new_body == body
|
36
|
+
body = new_body
|
37
|
+
end
|
38
|
+
body
|
39
|
+
end
|
40
|
+
|
41
|
+
def eval_ruby( ruby_code, file_name = @input_file, line = 0 )
|
42
|
+
eval ruby_code, binding, file_name, line
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_method( symbol, &block )
|
46
|
+
self.class.send :define_method, symbol, block
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_variable( key, val )
|
50
|
+
@variables[ key ] = val
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_variables( new_variables )
|
54
|
+
new_variables.each_pair { |k,v| set_variable k, v }
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_binding
|
58
|
+
binding
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
def erbify( template, file_name )
|
64
|
+
erb = ERB.new template
|
65
|
+
erb.filename = file_name
|
66
|
+
erb.result binding
|
67
|
+
end
|
68
|
+
|
69
|
+
def define_methods
|
70
|
+
@state.tags.each_pair do |name,impl|
|
71
|
+
impl.define_in self
|
72
|
+
end
|
73
|
+
@state.functions.each_pair do |name,impl|
|
74
|
+
impl.define_in self
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
alias original_missing method_missing
|
79
|
+
|
80
|
+
def method_missing( symbol, *args )
|
81
|
+
original_missing symbol, *args unless @variables.has_key? symbol
|
82
|
+
raise "Variable collides with existing symbol" if self.respond_to? symbol
|
83
|
+
|
84
|
+
self.class.send :define_method, symbol do
|
85
|
+
@variables[ symbol ]
|
86
|
+
end
|
87
|
+
self.class.send :define_method, "#{symbol}=".to_sym do |val|
|
88
|
+
@variables[ symbol ] = val
|
89
|
+
end
|
90
|
+
|
91
|
+
send symbol, *args
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require 'util/chained_hash'
|
3
|
+
require 'util/system_logger'
|
4
|
+
|
5
|
+
module BxMS
|
6
|
+
|
7
|
+
class Functions < Util::ChainedHash
|
8
|
+
|
9
|
+
def initialize( parent = nil )
|
10
|
+
super parent
|
11
|
+
@logger = Util::SystemLogger.new 'BxMS::Functions'
|
12
|
+
end
|
13
|
+
|
14
|
+
def load( file_name )
|
15
|
+
return unless File.file? file_name
|
16
|
+
function_name = File.basename file_name, '.*'
|
17
|
+
function_code = IO.read file_name
|
18
|
+
self[ function_name ] = Function.new function_code, file_name
|
19
|
+
@logger.info "Loaded function #{function_name} from #{file_name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class Function
|
25
|
+
|
26
|
+
attr_reader :file_name
|
27
|
+
|
28
|
+
def initialize( code, file_name )
|
29
|
+
@code = code
|
30
|
+
@file_name = file_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def define_in( context )
|
34
|
+
eval @code, context.get_binding, @file_name
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
require 'bxms/root_state'
|
3
|
+
require 'bxms/state'
|
4
|
+
|
5
|
+
module BxMS
|
6
|
+
|
7
|
+
class Processor
|
8
|
+
|
9
|
+
DIRECT_IGNORES = [ '.', '..', '.functions', '.rules', '.tags', '.templates', '.svn', 'CVS' ]
|
10
|
+
|
11
|
+
attr_writer :verbose
|
12
|
+
|
13
|
+
def process( from_to_hash )
|
14
|
+
from_dir = from_to_hash[ :from ]
|
15
|
+
to_dir = from_to_hash[ :to ]
|
16
|
+
|
17
|
+
root = RootState.new from_dir, to_dir
|
18
|
+
recurse root
|
19
|
+
end
|
20
|
+
|
21
|
+
def recurse( parent_state, directory = nil )
|
22
|
+
state = State.new parent_state, directory
|
23
|
+
puts "Processing #{state.input_dir} to #{state.output_dir}" if @verbose
|
24
|
+
|
25
|
+
sub_dirs = []
|
26
|
+
list state.input_dir do |file|
|
27
|
+
sub_dirs << file if File.directory? file
|
28
|
+
handle_file file, state if File.file? file
|
29
|
+
end
|
30
|
+
|
31
|
+
sub_dirs.each do |dir|
|
32
|
+
recurse state, dir
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def list( directory )
|
37
|
+
Dir.foreach( directory ) do |file|
|
38
|
+
next if DIRECT_IGNORES.include? file
|
39
|
+
yield File.join( directory, file )
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def handle_file( file_name, state )
|
44
|
+
state.set_variable :current_file_name, file_name
|
45
|
+
state.set_variable :current_file, File.new( file_name )
|
46
|
+
rule = state.rules[ file_name ]
|
47
|
+
puts "#{rule.name} #{file_name} to #{state.output_dir}" if @verbose
|
48
|
+
rule.apply_to file_name, state
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
require 'bxms/functions'
|
3
|
+
require 'bxms/tags'
|
4
|
+
require 'bxms/variables'
|
5
|
+
|
6
|
+
module BxMS
|
7
|
+
|
8
|
+
class RootState
|
9
|
+
|
10
|
+
attr_reader :source_dir
|
11
|
+
attr_reader :target_dir
|
12
|
+
|
13
|
+
attr_reader :functions
|
14
|
+
attr_reader :rules
|
15
|
+
attr_reader :tags
|
16
|
+
attr_reader :variables
|
17
|
+
|
18
|
+
def initialize( source_dir, target_dir )
|
19
|
+
@source_dir = source_dir
|
20
|
+
@target_dir = target_dir
|
21
|
+
|
22
|
+
@functions = Functions.new
|
23
|
+
@rules = Rules.new
|
24
|
+
@tags = Tags.new
|
25
|
+
@variables = Variables.new
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/src/bxms/rules.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
module BxMS
|
3
|
+
|
4
|
+
RULES_DIR = 'rules'
|
5
|
+
|
6
|
+
class Rules
|
7
|
+
|
8
|
+
def initialize( parent = nil )
|
9
|
+
@logger = Util::SystemLogger.new 'BxMS::Rules'
|
10
|
+
@parent = parent
|
11
|
+
@rules = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def []( filename )
|
15
|
+
@rules.each do |rule|
|
16
|
+
return rule.command if rule.matches? filename
|
17
|
+
end
|
18
|
+
return @parent[ filename ] if @parent
|
19
|
+
raise "No rule for #{filename}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def load( file_name )
|
23
|
+
@logger.info "Loading rules from #{file_name}"
|
24
|
+
lines = File.readlines file_name
|
25
|
+
lines.each { |rule| add_rule rule }
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_rule( rule_spec )
|
29
|
+
pattern, command = rule_spec.chomp.split( /[ \t]+/ )
|
30
|
+
raise "Bad rule spec: #{rule_spec}" unless pattern && command
|
31
|
+
@rules << Rule.new( pattern, command )
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
class Rule
|
37
|
+
|
38
|
+
def initialize( pattern, command )
|
39
|
+
raise "Invalid pattern: #{pattern}" unless is_valid? pattern
|
40
|
+
raise "Invalid command: #{command}" unless is_valid? command
|
41
|
+
|
42
|
+
init_pattern pattern
|
43
|
+
init_command command
|
44
|
+
end
|
45
|
+
|
46
|
+
def matches?( filename )
|
47
|
+
@pattern =~ filename
|
48
|
+
end
|
49
|
+
|
50
|
+
def command
|
51
|
+
@command
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def is_valid?( input )
|
57
|
+
input && input.length > 0
|
58
|
+
end
|
59
|
+
|
60
|
+
def init_pattern( pattern )
|
61
|
+
pattern = Regexp.escape( pattern )
|
62
|
+
pattern = pattern.gsub( '\?', '.' ).gsub( '\*', '.*' )
|
63
|
+
@pattern = Regexp.new pattern
|
64
|
+
end
|
65
|
+
|
66
|
+
def init_command( command )
|
67
|
+
command_file = File.join RULES_DIR, ( command + '.rb' )
|
68
|
+
command_class = get_class_name command
|
69
|
+
|
70
|
+
load command_file
|
71
|
+
@command = eval "::Rules::#{command_class}Rule.new", binding
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_class_name( command_name )
|
75
|
+
parts = command_name.split '_'
|
76
|
+
parts.map! { |part| part.capitalize }
|
77
|
+
parts.join ''
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/src/bxms/state.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
|
2
|
+
require 'bxms/root_state'
|
3
|
+
require 'bxms/rules'
|
4
|
+
|
5
|
+
module BxMS
|
6
|
+
|
7
|
+
class State
|
8
|
+
|
9
|
+
attr_reader :input_dir
|
10
|
+
attr_reader :output_dir
|
11
|
+
attr_reader :relative_root
|
12
|
+
|
13
|
+
attr_reader :variables
|
14
|
+
attr_reader :functions
|
15
|
+
attr_reader :rules
|
16
|
+
attr_reader :tags
|
17
|
+
|
18
|
+
def initialize( parent, directory = nil )
|
19
|
+
@parent = parent
|
20
|
+
|
21
|
+
relative_dir = make_relative source_dir, directory
|
22
|
+
|
23
|
+
@input_dir = make_absolute source_dir, relative_dir
|
24
|
+
@output_dir = make_absolute target_dir, relative_dir
|
25
|
+
@relative_root = get_relative_root relative_dir
|
26
|
+
|
27
|
+
@variables = Variables.new parent.variables
|
28
|
+
@functions = Functions.new parent.functions
|
29
|
+
@rules = Rules.new parent.rules
|
30
|
+
@tags = Tags.new parent.tags
|
31
|
+
|
32
|
+
load_local @functions, '.functions/*.{rb}'
|
33
|
+
load_local @tags, '.tags/*'
|
34
|
+
load_local @rules, '.rules'
|
35
|
+
|
36
|
+
set_variables
|
37
|
+
end
|
38
|
+
|
39
|
+
def source_dir
|
40
|
+
@parent.source_dir
|
41
|
+
end
|
42
|
+
|
43
|
+
def target_dir
|
44
|
+
@parent.target_dir
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_root_file( file_name )
|
48
|
+
File.join source_dir, file_name
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_local_file( file_name )
|
52
|
+
File.join input_dir, file_name
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_output_file_for( input_file )
|
56
|
+
relative_file = make_relative source_dir, input_file
|
57
|
+
output_file = make_absolute target_dir, relative_file
|
58
|
+
FileUtils.mkdir_p File.dirname( output_file )
|
59
|
+
output_file
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_variable( key, val )
|
63
|
+
@variables[ key.to_sym ] = val
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
def set_variables
|
69
|
+
set_variable :state, self
|
70
|
+
set_variable :input_dir, input_dir
|
71
|
+
set_variable :output_dir, output_dir
|
72
|
+
set_variable :relative_root, relative_root
|
73
|
+
end
|
74
|
+
|
75
|
+
def load_local( container, pattern )
|
76
|
+
full_pattern = get_local_file pattern
|
77
|
+
Dir.glob( full_pattern ) { |file_name| container.load file_name }
|
78
|
+
end
|
79
|
+
|
80
|
+
def make_relative( parent_dir, file_name )
|
81
|
+
return '' unless file_name
|
82
|
+
pattern = Regexp.escape parent_dir
|
83
|
+
get_valid file_name.sub( Regexp.new( "^#{pattern}\/?" ), '' )
|
84
|
+
end
|
85
|
+
|
86
|
+
def make_absolute( parent_dir, file_name )
|
87
|
+
return parent_dir unless file_name
|
88
|
+
get_valid File.join( parent_dir, file_name )
|
89
|
+
end
|
90
|
+
|
91
|
+
def get_relative_root( relative_dir )
|
92
|
+
relative_root = "#{relative_dir}".gsub( /[^\/]+/, '..' )
|
93
|
+
relative_root = '.' unless relative_root.length > 0
|
94
|
+
relative_root
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_valid( directory )
|
98
|
+
raise "Invalid directory" unless directory && directory.size > 1
|
99
|
+
directory.chop! if directory[ -1, 1 ] == File::SEPARATOR
|
100
|
+
directory
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|