txprails 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +50 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/VERSION_NAME +1 -0
- data/bin/txprails +9 -0
- data/ext/txparse/Makefile +157 -0
- data/ext/txparse/extconf.rb +8 -0
- data/ext/txparse/test_txp.rb +65 -0
- data/ext/txparse/txparse.cpp +139 -0
- data/ext/txparse/txparse.h +15 -0
- data/ext/txparse/txparse_lib.cpp +191 -0
- data/ext/txparse/txparse_lib.h +17 -0
- data/ext/txparse/txparse_tag.cpp +109 -0
- data/ext/txparse/txparse_tag.h +7 -0
- data/lib/init_rails.rb +16 -0
- data/lib/txprails/commands.rb +88 -0
- data/lib/txprails/template.rb +29 -0
- data/lib/txprails/util.rb +44 -0
- data/lib/txprails/version.rb +64 -0
- data/lib/txprails.rb +44 -0
- data/test/helper.rb +10 -0
- data/test/test_txprails.rb +7 -0
- data/txprails.gemspec +73 -0
- metadata +91 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "txparse.h"
|
3
|
+
|
4
|
+
//---------------------------------------------------------------------------
|
5
|
+
const string TXPDictSpaces = " \t\r\n";
|
6
|
+
const string TXPDictWordLim = " \t\r\n,<>/=";
|
7
|
+
const string TXPDictSingleQuote = "'";
|
8
|
+
const string TXPDictDoubleQuote = "\"";
|
9
|
+
|
10
|
+
string txp_domain_str = "dmstk";
|
11
|
+
|
12
|
+
//---------------------------------------------------------------------------
|
13
|
+
static bool txp_isspace(string::const_iterator iter)
|
14
|
+
{
|
15
|
+
return find(TXPDictSpaces.begin(), TXPDictSpaces.end(), *iter) != TXPDictSpaces.end();
|
16
|
+
}
|
17
|
+
|
18
|
+
//---------------------------------------------------------------------------
|
19
|
+
static bool txp_valid_chars(
|
20
|
+
string::const_iterator iter,
|
21
|
+
string::const_iterator end
|
22
|
+
)
|
23
|
+
{
|
24
|
+
if (*iter == '/') { iter++; end++; }
|
25
|
+
for (; iter != end; ++iter) {
|
26
|
+
if (::isspace(*iter)) return false;
|
27
|
+
if (*iter == ':') return true;
|
28
|
+
if (!::isalpha(*iter)) return false;
|
29
|
+
}
|
30
|
+
return false; // No se encontró los dos puntos...
|
31
|
+
}
|
32
|
+
|
33
|
+
//---------------------------------------------------------------------------
|
34
|
+
string::const_iterator txp_find_tag(
|
35
|
+
string::const_iterator iter,
|
36
|
+
string::const_iterator end
|
37
|
+
)
|
38
|
+
{
|
39
|
+
// Encontramos un TAG de plantilla cuando tengamos "<" + [a-z]{3} + ":"
|
40
|
+
// O también cuando tengamos "</" ya que es de cierre...
|
41
|
+
while (iter != end) {
|
42
|
+
if ((*iter == '<') && (end - iter > 5) && txp_valid_chars(iter+1, iter+7))
|
43
|
+
return iter;
|
44
|
+
++iter;
|
45
|
+
}
|
46
|
+
return iter;
|
47
|
+
}
|
48
|
+
|
49
|
+
//---------------------------------------------------------------------------
|
50
|
+
string::const_iterator txp_find_close(
|
51
|
+
string::const_iterator iter,
|
52
|
+
string::const_iterator end
|
53
|
+
)
|
54
|
+
{
|
55
|
+
// Encontramos un final de TAG cuando tengamos ">"
|
56
|
+
for (; iter != end; ++iter) {
|
57
|
+
if (*iter == '>') return iter+1;
|
58
|
+
}
|
59
|
+
return iter;
|
60
|
+
}
|
61
|
+
|
62
|
+
//---------------------------------------------------------------------------
|
63
|
+
string::const_iterator txp_find_par(
|
64
|
+
string::const_iterator begin,
|
65
|
+
string::const_iterator end,
|
66
|
+
VALUE tag
|
67
|
+
)
|
68
|
+
{
|
69
|
+
// TODO:
|
70
|
+
// Tenemos que hacer el mismo recorrido a partir de "begin" que en el
|
71
|
+
// bucle de parsing, pero esta vez sólo para encontrar un tag coincidente
|
72
|
+
// con el que nos pasan... Todo esto no es más que una prueba, habría que
|
73
|
+
// hacer un algoritmo más "robusto" para esto (Por ejemplo con pilas para
|
74
|
+
// encontrar un tag balanceado, ahora no pueden estar anidados.)
|
75
|
+
|
76
|
+
string::const_iterator old;
|
77
|
+
|
78
|
+
while (begin != end) {
|
79
|
+
begin = txp_find_tag(begin, end);
|
80
|
+
if (begin != end) {
|
81
|
+
// Estamos en un tag...
|
82
|
+
old = begin;
|
83
|
+
begin = txp_find_close(begin, end);
|
84
|
+
if (begin != end) {
|
85
|
+
VALUE tag_txt = rb_str_new2(string(old, begin).c_str());
|
86
|
+
VALUE new_tag = rb_class_new_instance(1, &tag_txt, rb_const_get(mTXParse, rb_intern("Tag")));
|
87
|
+
/*
|
88
|
+
printf(":::: SEARCHING PAR (D:'%s' vs '%s', N:'%s' vs. '%s')\n"
|
89
|
+
, RSTRING(rb_iv_get(tag, "@domain"))->ptr
|
90
|
+
, RSTRING(rb_iv_get(new_tag, "@domain"))->ptr
|
91
|
+
, RSTRING(rb_iv_get(tag, "@name"))->ptr
|
92
|
+
, RSTRING(rb_iv_get(new_tag, "@name"))->ptr
|
93
|
+
);
|
94
|
+
*/
|
95
|
+
|
96
|
+
// Vale, comprobamos que el tag se llama igual...
|
97
|
+
if (!rb_str_cmp(rb_iv_get(tag, "@domain"), rb_iv_get(new_tag, "@domain")) &&
|
98
|
+
!rb_str_cmp(rb_iv_get(tag, "@name"), rb_iv_get(new_tag, "@name"))) {
|
99
|
+
// printf(":::: FOUND!!!\n");
|
100
|
+
|
101
|
+
// Es el mismo TAG... ¿Es de cierre?
|
102
|
+
if (rb_iv_get(new_tag, "@is_close") == Qtrue) {
|
103
|
+
// printf(":::: New Tag is CLOSE\n");
|
104
|
+
// printf(":::: DBG: [%s]\n", string(old, end).c_str());
|
105
|
+
return old;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
return end; // What else?
|
112
|
+
}
|
113
|
+
|
114
|
+
|
115
|
+
#define DEBUG_POS(str, pos) \
|
116
|
+
{\
|
117
|
+
string strdebug = string(str.size(), ' '); \
|
118
|
+
strdebug[pos] = '$'; \
|
119
|
+
printf("|%s|\n", str.c_str()); \
|
120
|
+
printf("|%s|\n", strdebug.c_str()); \
|
121
|
+
}
|
122
|
+
|
123
|
+
//---------------------------------------------------------------------------
|
124
|
+
void txp_parse_tag(const string tag, string &domain, string &name, map<string, string> &attrs, bool &close)
|
125
|
+
{
|
126
|
+
string::size_type pos = 0, pos2;
|
127
|
+
|
128
|
+
if ((tag.size() == 0) || (tag[pos++] != '<')) {
|
129
|
+
rb_raise(rb_eSyntaxError, "Tag should begin with '<'");
|
130
|
+
// rb_raise no retorna...
|
131
|
+
}
|
132
|
+
|
133
|
+
if (tag[pos] == '/') {
|
134
|
+
close = true;
|
135
|
+
pos++;
|
136
|
+
}
|
137
|
+
|
138
|
+
pos2 = tag.find_first_of(":/> \t\r\n", pos);
|
139
|
+
if ((pos2 == string::npos) || (tag[pos2] != ':')) {
|
140
|
+
rb_warn("TAG Should have a 'domain'. Assuming 'dmstk'");
|
141
|
+
// rb_raise(rb_eSyntaxError, "Tag should have a domain.");
|
142
|
+
domain = "dmstk";
|
143
|
+
name = string(tag, pos, pos2 - pos);
|
144
|
+
} else {
|
145
|
+
domain = string(tag, pos, pos2 - pos);
|
146
|
+
pos = pos2 + 1;
|
147
|
+
pos2 = tag.find_first_of(":/> \t\r\n", pos);
|
148
|
+
name = string(tag, pos, pos2 - pos);
|
149
|
+
}
|
150
|
+
|
151
|
+
// Si soy tag de cierre, no debo tener attributos.
|
152
|
+
if (close) return;
|
153
|
+
|
154
|
+
// Parseado el dominio y el nombre, saltamos a los attributos...
|
155
|
+
pos = tag.find_first_not_of(" \t\r\n", pos2);
|
156
|
+
if ((pos == string::npos) || (pos == '>')) return;
|
157
|
+
|
158
|
+
while ((pos != string::npos) && (tag[pos] != '>')) {
|
159
|
+
// Caso especial del tag de autocierre y el final de tag '>'
|
160
|
+
if ((tag[pos] == '/') && (tag[pos+1] == '>')) {
|
161
|
+
close = true; // autoclose ??
|
162
|
+
pos = string::npos;
|
163
|
+
break;
|
164
|
+
}
|
165
|
+
|
166
|
+
pos2 = tag.find_first_of(" \t\r\n,<>/=", pos);
|
167
|
+
string attrname = string(tag, pos, pos2 - pos);
|
168
|
+
string attrval = "";
|
169
|
+
|
170
|
+
pos2 = tag.find_first_not_of(" \t\r\n", pos2);
|
171
|
+
if ((pos2 != string::npos) && (tag[pos2]=='=')) {
|
172
|
+
// Parseando valor de atributo
|
173
|
+
pos2 = tag.find_first_not_of(" \t\r\n", pos2+1);
|
174
|
+
|
175
|
+
switch (tag[pos2]) {
|
176
|
+
case '\'': pos = pos2+1; pos2 = tag.find_first_of("'", pos); break;
|
177
|
+
case '"': pos = pos2+1; pos2 = tag.find_first_of("\"", pos); break;
|
178
|
+
default: pos = pos2; pos2 = tag.find_first_of(" \t\r\n"); break;
|
179
|
+
}
|
180
|
+
attrval = string(tag, pos, pos2 - pos);
|
181
|
+
} else {
|
182
|
+
// Atributo sin valores!! Asumimos --> nombre="nombre"
|
183
|
+
attrval = attrname;
|
184
|
+
}
|
185
|
+
|
186
|
+
attrs[attrname] = attrval;
|
187
|
+
|
188
|
+
// Tenemos que dejar "pos" en el siguiente atributo...
|
189
|
+
pos = tag.find_first_not_of(" \t\r\n", pos2+1);
|
190
|
+
}
|
191
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#ifndef TXPARSE_LIB
|
2
|
+
#define TXPARSE_LIB
|
3
|
+
|
4
|
+
#include <string>
|
5
|
+
#include <map>
|
6
|
+
|
7
|
+
using namespace std;
|
8
|
+
|
9
|
+
extern string txp_domain_str;
|
10
|
+
|
11
|
+
//---------------------------------------------------------------------------
|
12
|
+
string::const_iterator txp_find_tag(string::const_iterator iter, string::const_iterator end);
|
13
|
+
string::const_iterator txp_find_close(string::const_iterator iter, string::const_iterator end);
|
14
|
+
string::const_iterator txp_find_par(string::const_iterator begin, string::const_iterator end, VALUE tag);
|
15
|
+
void txp_parse_tag(const string tag, string &domain, string &name, map<string, string> &attrs, bool &close);
|
16
|
+
|
17
|
+
#endif
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "txparse.h"
|
3
|
+
|
4
|
+
extern "C" VALUE tag_initialize(VALUE self, VALUE orig)
|
5
|
+
{
|
6
|
+
string domain, name;
|
7
|
+
map<string, string> attrs;
|
8
|
+
bool is_close = false;
|
9
|
+
VALUE attr_hash = rb_hash_new();
|
10
|
+
|
11
|
+
rb_check_type(orig, T_STRING);
|
12
|
+
txp_parse_tag(string(RSTRING(orig)->ptr), domain, name, attrs, is_close);
|
13
|
+
|
14
|
+
/*
|
15
|
+
printf("PARSE-TAG DBG: ORIG='%s'\n", RSTRING(orig)->ptr);
|
16
|
+
printf(" DOMAIN='%s', NAME='%s'\n", domain.c_str(), name.c_str());
|
17
|
+
printf(" ATTRS(num)='%d', CLOSED='%c'\n", (int)attrs.size(), is_close ? 'Y' : 'N');
|
18
|
+
*/
|
19
|
+
|
20
|
+
if (attrs.size()) {
|
21
|
+
for (map<string, string>::const_iterator iter = attrs.begin()
|
22
|
+
; iter != attrs.end()
|
23
|
+
; ++iter)
|
24
|
+
{
|
25
|
+
rb_hash_aset(attr_hash, rb_str_new2((*iter).first.c_str()), rb_str_new2((*iter).second.c_str()));
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
rb_iv_set(self, "@name", rb_str_new2(name.c_str()));
|
30
|
+
rb_iv_set(self, "@domain", rb_str_new2(domain.c_str()));
|
31
|
+
rb_iv_set(self, "@is_close", is_close ? Qtrue : Qfalse);
|
32
|
+
rb_iv_set(self, "@attr", attr_hash);
|
33
|
+
rb_iv_set(self, "@orig", orig);
|
34
|
+
return self;
|
35
|
+
}
|
36
|
+
|
37
|
+
extern "C" VALUE tag_name(VALUE self)
|
38
|
+
{
|
39
|
+
return rb_iv_get(self, "@name");
|
40
|
+
}
|
41
|
+
|
42
|
+
extern "C" VALUE tag_name_set(VALUE self, VALUE new_name)
|
43
|
+
{
|
44
|
+
return rb_iv_set(self, "@name", new_name);
|
45
|
+
}
|
46
|
+
|
47
|
+
|
48
|
+
extern "C" VALUE tag_domain(VALUE self)
|
49
|
+
{
|
50
|
+
return rb_iv_get(self, "@domain");
|
51
|
+
}
|
52
|
+
|
53
|
+
extern "C" VALUE tag_domain_set(VALUE self, VALUE new_domain)
|
54
|
+
{
|
55
|
+
return rb_iv_set(self, "@domain", new_domain);
|
56
|
+
}
|
57
|
+
|
58
|
+
extern "C" VALUE tag_thing(VALUE self)
|
59
|
+
{
|
60
|
+
return rb_iv_get(self, "@thing");
|
61
|
+
}
|
62
|
+
|
63
|
+
extern "C" VALUE tag_thing_set(VALUE self, VALUE new_thing)
|
64
|
+
{
|
65
|
+
return rb_iv_set(self, "@thing", new_thing);
|
66
|
+
}
|
67
|
+
|
68
|
+
extern "C" VALUE tag_attributes(VALUE self)
|
69
|
+
{
|
70
|
+
return rb_iv_get(self, "@attr");
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
extern "C" VALUE tag_is_close(VALUE self)
|
76
|
+
{
|
77
|
+
return rb_iv_get(self, "@is_close");
|
78
|
+
}
|
79
|
+
|
80
|
+
extern "C" VALUE tag_orig(VALUE self)
|
81
|
+
{
|
82
|
+
return rb_iv_get(self, "@orig");
|
83
|
+
}
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
VALUE mTXParseTag = Qnil;
|
89
|
+
void Init_TXParseTag()
|
90
|
+
{
|
91
|
+
// VALUE TXParse_Module = rb_define_module("TXParse");
|
92
|
+
mTXParseTag = rb_define_class_under(mTXParse, "Tag", rb_cObject);
|
93
|
+
|
94
|
+
rb_define_method(mTXParseTag, "initialize", RUBY_METHOD_FUNC(tag_initialize), 1);
|
95
|
+
|
96
|
+
rb_define_method(mTXParseTag, "name", RUBY_METHOD_FUNC(tag_name), 0);
|
97
|
+
rb_define_method(mTXParseTag, "name=", RUBY_METHOD_FUNC(tag_name_set), 1);
|
98
|
+
|
99
|
+
rb_define_method(mTXParseTag, "domain", RUBY_METHOD_FUNC(tag_domain), 0);
|
100
|
+
rb_define_method(mTXParseTag, "domain=", RUBY_METHOD_FUNC(tag_domain_set), 1);
|
101
|
+
|
102
|
+
rb_define_method(mTXParseTag, "thing", RUBY_METHOD_FUNC(tag_thing), 0);
|
103
|
+
rb_define_method(mTXParseTag, "thing=", RUBY_METHOD_FUNC(tag_thing_set), 1);
|
104
|
+
|
105
|
+
rb_define_method(mTXParseTag, "attr", RUBY_METHOD_FUNC(tag_attributes), 0);
|
106
|
+
|
107
|
+
rb_define_method(mTXParseTag, "close?", RUBY_METHOD_FUNC(tag_is_close), 0);
|
108
|
+
rb_define_method(mTXParseTag, "orig", RUBY_METHOD_FUNC(tag_orig), 0);
|
109
|
+
}
|
data/lib/init_rails.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
begin
|
2
|
+
require File.join(File.dirname(__FILE__), 'txprails') # From here
|
3
|
+
rescue LoadError
|
4
|
+
begin
|
5
|
+
require 'txprails' # From gem
|
6
|
+
rescue LoadError => e
|
7
|
+
# gems:install may be run to install TXPRails with the skeleton plugin
|
8
|
+
# but not the gem itself installed.
|
9
|
+
# Don't die if this is the case.
|
10
|
+
raise e unless defined?(Rake) && Rake.application.top_level_tasks.include?('gems:install')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Load TXPRails.
|
15
|
+
# TXPRails may be undefined if we're running gems:install.
|
16
|
+
TXPRails.init_rails if defined?(TXPRails)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module TXPRails
|
5
|
+
# This module handles miscelaneous command line utilities
|
6
|
+
class Commands
|
7
|
+
# @param args [Array<String>] The command-line arguments
|
8
|
+
def initialize(args)
|
9
|
+
@args = args
|
10
|
+
@options = {}
|
11
|
+
@options[:requires] = [] # ??
|
12
|
+
@options[:load_paths] = [] # ??
|
13
|
+
end
|
14
|
+
|
15
|
+
# Parses the command-line arguments and runs the executable.
|
16
|
+
# Calls `Kernel#exit` at the end, so it never returns.
|
17
|
+
def parse!
|
18
|
+
begin
|
19
|
+
@opts = OptionParser.new(&method(:set_opts))
|
20
|
+
@opts.parse!(@args)
|
21
|
+
@options
|
22
|
+
rescue Exception => e
|
23
|
+
raise e if e.is_a?(SystemExit)
|
24
|
+
|
25
|
+
$stderr.puts e.message
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
exit 0
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String] A description of the executable
|
32
|
+
def to_s
|
33
|
+
@opts.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
# Tells optparse how to parse the arguments
|
39
|
+
# available for all executables.
|
40
|
+
#
|
41
|
+
# This is meant to be overridden by subclasses
|
42
|
+
# so they can add their own options.
|
43
|
+
#
|
44
|
+
# @param opts [OptionParser]
|
45
|
+
def set_opts(opts)
|
46
|
+
opts.on_tail("-?", "-h", "--help", "Show this message") do
|
47
|
+
puts opts
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on_tail("-v", "--version", "Print version") do
|
52
|
+
puts("TXPRails #{::TXPRails.version[:string]}")
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on('--rails RAILS_DIR', "Install TXPRails from the Gem to a Rails project") do |dir|
|
57
|
+
original_dir = dir
|
58
|
+
dir = File.join(dir, 'vendor', 'plugins')
|
59
|
+
unless File.exists?(dir)
|
60
|
+
puts "Directory #{dir} doesn't exist"
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
|
64
|
+
dir = File.join(dir, 'txprails')
|
65
|
+
if File.exists?(dir)
|
66
|
+
print "Directory #{dir} already exists, overwrite [y/N]? "
|
67
|
+
exit if gets !~ /y/i
|
68
|
+
FileUtils.rm_rf(dir)
|
69
|
+
end
|
70
|
+
|
71
|
+
begin
|
72
|
+
Dir.mkdir(dir)
|
73
|
+
rescue SystemCallError
|
74
|
+
puts "Cannot create #{dir}"
|
75
|
+
exit
|
76
|
+
end
|
77
|
+
|
78
|
+
File.open(File.join(dir, 'init.rb'), 'w') do |file|
|
79
|
+
file << File.read(File.dirname(__FILE__) + "/../init_rails.rb")
|
80
|
+
end
|
81
|
+
|
82
|
+
puts "Haml plugin added to #{original_dir}"
|
83
|
+
exit
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Simple template initialization code
|
2
|
+
# Borrowed ideas from Haml, but VERY much simplyfied
|
3
|
+
# WARNING: We choose to use the plugin approach, so NO RAILS < 2.1.0 compatibility!
|
4
|
+
|
5
|
+
module TXPRails
|
6
|
+
|
7
|
+
class TXPTemplateHandler < TXPRails::Util.av_template_class(:Handler)
|
8
|
+
include TXP
|
9
|
+
|
10
|
+
def initialize(view)
|
11
|
+
@view = view
|
12
|
+
end
|
13
|
+
|
14
|
+
def render(template, local_assigns = {})
|
15
|
+
parse(template.source)
|
16
|
+
end
|
17
|
+
|
18
|
+
def compilable?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
if defined? ActionView::Template and ActionView::Template.respond_to? :register_template_handler
|
26
|
+
ActionView::Template
|
27
|
+
else
|
28
|
+
ActionView::Base
|
29
|
+
end.register_template_handler(:txp, TXPRails::TXPTemplateHandler)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module TXPRails
|
2
|
+
# A module containing various useful functions.
|
3
|
+
module Util
|
4
|
+
extend self
|
5
|
+
|
6
|
+
# An array of ints representing the Ruby version number.
|
7
|
+
RUBY_VERSION = ::RUBY_VERSION.split(".").map {|s| s.to_i}
|
8
|
+
|
9
|
+
# Returns the path of a file relative to the Haml root directory.
|
10
|
+
#
|
11
|
+
# @param file [String] The filename relative to the Haml root
|
12
|
+
# @return [String] The filename relative to the the working directory
|
13
|
+
def scope(file)
|
14
|
+
File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), file)
|
15
|
+
end
|
16
|
+
|
17
|
+
## Cross Rails Version Compatibility
|
18
|
+
|
19
|
+
# Returns the root of the Rails application,
|
20
|
+
# if this is running in a Rails context.
|
21
|
+
# Returns `nil` if no such root is defined.
|
22
|
+
#
|
23
|
+
# @return [String, nil]
|
24
|
+
def rails_root
|
25
|
+
return Rails.root.to_s if defined?(Rails.root)
|
26
|
+
return RAILS_ROOT.to_s if defined?(RAILS_ROOT)
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns an ActionView::Template* class.
|
31
|
+
# In pre-3.0 versions of Rails, most of these classes
|
32
|
+
# were of the form `ActionView::TemplateFoo`,
|
33
|
+
# while afterwards they were of the form `ActionView::Template::Foo`.
|
34
|
+
#
|
35
|
+
# @param name [#to_s] The name of the class to get.
|
36
|
+
# For example, `:Error` will return `ActionView::TemplateError`
|
37
|
+
# or `ActionView::Template::Error`.
|
38
|
+
def av_template_class(name)
|
39
|
+
return ActionView.const_get("Template#{name}") if ActionView.const_defined?("Template#{name}")
|
40
|
+
return ActionView::Template.const_get(name.to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'txprails/util'
|
2
|
+
|
3
|
+
module TXPRails
|
4
|
+
# Handles TXPRails version-reporting.
|
5
|
+
# TXPRails not only reports the standard three version numbers,
|
6
|
+
# but its Git revision hash as well,
|
7
|
+
# if it was installed from Git.
|
8
|
+
module Version
|
9
|
+
include TXPRails::Util
|
10
|
+
|
11
|
+
# Returns a hash representing the version of TXPRails.
|
12
|
+
# The `:major`, `:minor`, and `:teeny` keys have their respective numbers as Fixnums.
|
13
|
+
# The `:name` key has the name of the version.
|
14
|
+
# The `:string` key contains a human-readable string representation of the version.
|
15
|
+
# The `:number` key is the major, minor, and teeny keys separated by periods.
|
16
|
+
# If TXPRails is checked out from Git, the `:rev` key will have the revision hash.
|
17
|
+
# For example:
|
18
|
+
#
|
19
|
+
# {
|
20
|
+
# :string => "2.1.0.9616393",
|
21
|
+
# :rev => "9616393b8924ef36639c7e82aa88a51a24d16949",
|
22
|
+
# :number => "2.1.0",
|
23
|
+
# :major => 2, :minor => 1, :teeny => 0
|
24
|
+
# }
|
25
|
+
#
|
26
|
+
# @return [{Symbol => String/Fixnum}] The version hash
|
27
|
+
def version
|
28
|
+
return @@version if defined?(@@version)
|
29
|
+
|
30
|
+
numbers = File.read(scope('VERSION')).strip.split('.').map { |n| n.to_i }
|
31
|
+
name = File.read(scope('VERSION_NAME')).strip
|
32
|
+
@@version = {
|
33
|
+
:major => numbers[0],
|
34
|
+
:minor => numbers[1],
|
35
|
+
:teeny => numbers[2],
|
36
|
+
:name => name
|
37
|
+
}
|
38
|
+
@@version[:number] = [:major, :minor, :teeny].map { |comp| @@version[comp] }.compact.join('.')
|
39
|
+
@@version[:string] = @@version[:number].dup
|
40
|
+
|
41
|
+
if File.exists?(scope('REVISION'))
|
42
|
+
rev = File.read(scope('REVISION')).strip
|
43
|
+
rev = nil if rev !~ /^([a-f0-9]+|\(.*\))$/
|
44
|
+
end
|
45
|
+
|
46
|
+
if (rev.nil? || rev == '(unknown)') && File.exists?(scope('.git/HEAD'))
|
47
|
+
rev = File.read(scope('.git/HEAD')).strip
|
48
|
+
if rev =~ /^ref: (.*)$/
|
49
|
+
rev = File.read(scope(".git/#{$1}")).strip
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if rev
|
54
|
+
@@version[:rev] = rev
|
55
|
+
unless rev[0] == ?(
|
56
|
+
@@version[:string] << "." << rev[0...7]
|
57
|
+
end
|
58
|
+
@@version[:string] << " (#{name})"
|
59
|
+
end
|
60
|
+
|
61
|
+
@@version
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/txprails.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'txprails/txparse'
|
2
|
+
require 'txprails/version'
|
3
|
+
|
4
|
+
module TXPRails
|
5
|
+
extend TXPRails::Version
|
6
|
+
|
7
|
+
# A string representing the version of TXPRails.
|
8
|
+
# A more fine-grained representation is available from TXPRails.version.
|
9
|
+
VERSION = version[:string] unless defined?(TXPRails::VERSION)
|
10
|
+
|
11
|
+
# Initializes TXPRails for Rails.
|
12
|
+
#
|
13
|
+
# This method is called by `init.rb`,
|
14
|
+
# which is run by Rails on startup.
|
15
|
+
# We use it rather than putting stuff straight into `init.rb`
|
16
|
+
# so we can change the initialization behavior
|
17
|
+
# without modifying the file itself.
|
18
|
+
#
|
19
|
+
def self.init_rails
|
20
|
+
%w[txprails/template].each {|f| require f}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'txprails/util'
|
25
|
+
|
26
|
+
module TXP
|
27
|
+
include TXParse
|
28
|
+
|
29
|
+
def txp_doc(tag)
|
30
|
+
"<!DOCTYPE html>"
|
31
|
+
end
|
32
|
+
|
33
|
+
def txp_content(tag)
|
34
|
+
if content_for_layout = @view.instance_variable_get("@content_for_layout")
|
35
|
+
parse(content_for_layout)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def txp_include(tag)
|
40
|
+
@view.render :partial => tag.attr["name"]
|
41
|
+
end
|
42
|
+
|
43
|
+
# self.extend self
|
44
|
+
end
|
data/test/helper.rb
ADDED