ymdp 0.0.3
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 +17 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/application_view/application_view.rb +210 -0
- data/lib/application_view/asset_tag_helper.rb +106 -0
- data/lib/application_view/commands/generate.rb +3 -0
- data/lib/application_view/compiler/template_compiler.rb +417 -0
- data/lib/application_view/config.rb +39 -0
- data/lib/application_view/environment.rb +29 -0
- data/lib/application_view/generator/base.rb +15 -0
- data/lib/application_view/generator/templates/javascript.js +51 -0
- data/lib/application_view/generator/templates/stylesheet.css +5 -0
- data/lib/application_view/generator/templates/translation.pres +8 -0
- data/lib/application_view/generator/templates/view.html.haml +8 -0
- data/lib/application_view/generator/view.rb +170 -0
- data/lib/application_view/helpers.rb +4 -0
- data/lib/application_view/processor/compressor.rb +81 -0
- data/lib/application_view/processor/processor.rb +132 -0
- data/lib/application_view/processor/validator.rb +125 -0
- data/lib/application_view/support/file.rb +54 -0
- data/lib/application_view/support/form_post.rb +58 -0
- data/lib/application_view/support/g.rb +11 -0
- data/lib/application_view/support/growl.rb +36 -0
- data/lib/application_view/support/timer.rb +40 -0
- data/lib/application_view/support/w3c.rb +22 -0
- data/lib/application_view/tag_helper.rb +147 -0
- data/lib/application_view/translator/base.rb +387 -0
- data/lib/application_view/translator/blank.rb +58 -0
- data/lib/application_view/translator/ymdp_translate.rb +92 -0
- data/lib/ymdp.rb +1 -0
- data/test/helper.rb +10 -0
- data/test/test_ymdp.rb +4 -0
- data/ymdp.gemspec +77 -0
- metadata +92 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'support/file'
|
2
|
+
|
3
|
+
module ApplicationView
|
4
|
+
module Validator
|
5
|
+
class Base
|
6
|
+
extend ApplicationView::Config
|
7
|
+
extend ApplicationView::FileSupport
|
8
|
+
end
|
9
|
+
|
10
|
+
class HTML < Base
|
11
|
+
def self.validate(path)
|
12
|
+
html_display_path = display_path(path)
|
13
|
+
|
14
|
+
doctype = CONFIG["doctype"] || "HTML 4.0 Transitional"
|
15
|
+
|
16
|
+
resp = post_file_to_w3c_validator(path, doctype)
|
17
|
+
html = resp.read_body
|
18
|
+
if html.include? "[Valid]"
|
19
|
+
$stdout.puts " #{html_display_path} validating . . . OK"
|
20
|
+
else
|
21
|
+
log_path = "#{TMP_PATH}/#{File.basename(path)}_errors.html"
|
22
|
+
$stdout.puts " #{html_display_path} is not valid HTML, writing to #{display_path(log_path)}"
|
23
|
+
$stdout.puts
|
24
|
+
$stdout.puts " To view errors:"
|
25
|
+
$stdout.puts " open #{display_path(log_path)}"
|
26
|
+
$stdout.puts
|
27
|
+
File.open(log_path,'w') { |f| f.puts html }
|
28
|
+
$stdout.puts " Viewing errors..."
|
29
|
+
|
30
|
+
g("HTML validation errors found")
|
31
|
+
system "open #{log_path}"
|
32
|
+
raise "Invalid HTML"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class JavaScript < Base
|
38
|
+
def self.validate?
|
39
|
+
validate_embedded_js?
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.validate(filename)
|
43
|
+
if validate?
|
44
|
+
validate_javascript(filename)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.use_jslint_settings?
|
49
|
+
!jslint_settings.blank?
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.jslint_settings
|
53
|
+
<<-JSLINT
|
54
|
+
/*jslint bitwise: true, browser: true, evil: true, eqeqeq: true, immed: true, newcap: true, onevar: false, plusplus: true, regexp: true, undef: true, sub: true */
|
55
|
+
/*global YAHOO, openmail, OpenMailIntl, _gat, unescape, $, $$, $A, $H, $R, $w, $div, Event, Effect, Behavior, Try, PeriodicalExecuter, Element, identify, Sortable, window, I18n, Identity, Logger, OIB, Tags, ABTesting, Flash, Debug */
|
56
|
+
JSLINT
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.jslint_settings_count
|
60
|
+
jslint_settings.to_s.split("\n").size
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.pre_process(content)
|
64
|
+
content
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.validate_javascript(path)
|
68
|
+
display = display_path(path)
|
69
|
+
$stdout.print " #{display} validating . . . "
|
70
|
+
output = ""
|
71
|
+
|
72
|
+
File.open(path) do |f|
|
73
|
+
output = f.read
|
74
|
+
end
|
75
|
+
|
76
|
+
output = pre_process(output)
|
77
|
+
|
78
|
+
js_fragment_path = File.expand_path("#{TMP_PATH}/#{File.basename(path)}_fragment")
|
79
|
+
fragment_display_path = display_path(js_fragment_path)
|
80
|
+
|
81
|
+
unless File.exists?(js_fragment_path)
|
82
|
+
File.open(js_fragment_path,'w') do |f|
|
83
|
+
f.puts jslint_settings if use_jslint_settings?
|
84
|
+
f.puts output
|
85
|
+
end
|
86
|
+
|
87
|
+
results = `java org.mozilla.javascript.tools.shell.Main ./script/jslint.js #{js_fragment_path}`
|
88
|
+
|
89
|
+
if results =~ /jslint: No problems found/
|
90
|
+
$stdout.puts "OK"
|
91
|
+
else
|
92
|
+
$stdout.puts "errors found!"
|
93
|
+
results.split("\n").each do |result|
|
94
|
+
if result =~ /line (\d+) character (\d+): (.*)/
|
95
|
+
line_number = $1.to_i
|
96
|
+
error = "Error at #{fragment_display_path} line #{line_number-jslint_settings_count} character #{$2}: #{$3}"
|
97
|
+
error += get_line_from_file(js_fragment_path, line_number)
|
98
|
+
|
99
|
+
$stdout.puts error
|
100
|
+
end
|
101
|
+
end
|
102
|
+
message = "Javascript Errors embedded in #{display}"
|
103
|
+
g(message)
|
104
|
+
raise message
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class JSON < JavaScript
|
111
|
+
def self.validate?
|
112
|
+
validate_json_assets?
|
113
|
+
end
|
114
|
+
|
115
|
+
def pre_process(output)
|
116
|
+
output = output.gsub("\\u003C", "HELLO")
|
117
|
+
output = output.gsub("\\u003E", "HELLO")
|
118
|
+
output
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.jslint_settings
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ApplicationView
|
2
|
+
module FileSupport
|
3
|
+
def confirm_overwrite(path)
|
4
|
+
if File.exists?(path)
|
5
|
+
puts "File exists: #{display_path(path)}"
|
6
|
+
print " overwrite? (y/n)"
|
7
|
+
answer = $stdin.gets
|
8
|
+
|
9
|
+
answer =~ /^y/i
|
10
|
+
else
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# friendlier display of paths
|
16
|
+
def display_path(path)
|
17
|
+
path = File.expand_path(path)
|
18
|
+
path.gsub(BASE_PATH, "")
|
19
|
+
end
|
20
|
+
|
21
|
+
# saves the output string to the filename given
|
22
|
+
#
|
23
|
+
def save_to_file(output, filename)
|
24
|
+
unless File.exists?(filename)
|
25
|
+
File.open(filename, "w") do |w|
|
26
|
+
w.write(output)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# given a path and line number, returns the line and two lines previous
|
32
|
+
#
|
33
|
+
def get_line_from_file(path, line_number)
|
34
|
+
line_number = line_number.to_i
|
35
|
+
output = ""
|
36
|
+
lines = []
|
37
|
+
|
38
|
+
File.open(path) do |f|
|
39
|
+
lines = f.readlines
|
40
|
+
end
|
41
|
+
|
42
|
+
output += "\n"
|
43
|
+
|
44
|
+
3.times do |i|
|
45
|
+
line = lines[line_number-(3-i)]
|
46
|
+
output += line if line
|
47
|
+
end
|
48
|
+
|
49
|
+
output += "\n"
|
50
|
+
|
51
|
+
output
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# from http://devlicio.us/blogs/sergio_pereira/archive/2008/04/02/xhtml-validation-script-using-ruby.aspx
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'mime/types'
|
5
|
+
require 'net/http'
|
6
|
+
require 'CGI'
|
7
|
+
|
8
|
+
class FormField
|
9
|
+
attr_accessor :name, :value
|
10
|
+
def initialize( name, value )
|
11
|
+
@name = name
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_form_data
|
16
|
+
field = CGI::escape(@name)
|
17
|
+
"Content-Disposition: form-data; name=\"#{field}\"" +
|
18
|
+
"\r\n\r\n#{@value}\r\n"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class FileField
|
23
|
+
attr_accessor :name, :path, :content
|
24
|
+
def initialize( name, path, content )
|
25
|
+
@name = name
|
26
|
+
@path = "#{path}.html"
|
27
|
+
@content = content
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_form_data
|
31
|
+
"Content-Disposition: form-data; " +
|
32
|
+
"name=\"#{CGI::escape(@name)}\"; " +
|
33
|
+
"filename=\"#{@path}\"\r\n" +
|
34
|
+
"Content-Transfer-Encoding: binary\r\n" +
|
35
|
+
"Content-Type: #{MIME::Types.type_for(@path)}" +
|
36
|
+
"\r\n\r\n#{@content}\r\n"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class MultipartPost
|
41
|
+
SEPARATOR = 'willvalidate-aaaaaabbbb0000'
|
42
|
+
REQ_HEADER = {
|
43
|
+
"Content-type" => "multipart/form-data, boundary=#{SEPARATOR} "
|
44
|
+
}
|
45
|
+
|
46
|
+
def self.build_form_data ( form_fields )
|
47
|
+
fields = []
|
48
|
+
form_fields.each do |key, value|
|
49
|
+
if value.instance_of?(File)
|
50
|
+
fields << FileField.new(key.to_s, value.path, value.read)
|
51
|
+
else
|
52
|
+
fields << FormField.new(key.to_s, value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
fields.collect {|f| "--#{SEPARATOR}\r\n#{f.to_form_data}" }.join("") +
|
56
|
+
"--#{SEPARATOR}--"
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ruby-growl'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
$g_host ||= "localhost"
|
6
|
+
$g_priority ||= 0
|
7
|
+
$g_sticky ||= true
|
8
|
+
|
9
|
+
module Kernel
|
10
|
+
def growl(*args)
|
11
|
+
options = {}
|
12
|
+
if args.last.class == Hash
|
13
|
+
options = args.pop
|
14
|
+
end
|
15
|
+
|
16
|
+
title = options[:title] || 'g'
|
17
|
+
g = Growl.new $g_host, title, [$0]
|
18
|
+
|
19
|
+
messages =
|
20
|
+
if args.empty?
|
21
|
+
['g!']
|
22
|
+
else
|
23
|
+
args.map { |i| i.pretty_inspect }
|
24
|
+
end
|
25
|
+
|
26
|
+
messages.each { |i| g.notify $0, title, i, $g_priority, $g_sticky }
|
27
|
+
|
28
|
+
if args.empty?
|
29
|
+
nil
|
30
|
+
elsif args.size == 1
|
31
|
+
args.first
|
32
|
+
else
|
33
|
+
args
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ApplicationView
|
2
|
+
module Support
|
3
|
+
module Timer
|
4
|
+
def time(message="")
|
5
|
+
start_time = Time.now
|
6
|
+
yield
|
7
|
+
end_time = Time.now
|
8
|
+
put_elapsed_time(start_time, end_time, message)
|
9
|
+
end
|
10
|
+
|
11
|
+
def put_elapsed_time(start_time, end_time, message="")
|
12
|
+
seconds = end_time - start_time
|
13
|
+
if seconds > 59
|
14
|
+
minutes = seconds / 60.0
|
15
|
+
seconds = (minutes - minutes.to_i) * 60
|
16
|
+
|
17
|
+
m = minutes.to_i > 1 ? "minutes" : "minute"
|
18
|
+
elapsed_time = "#{minutes.to_i} #{m}"
|
19
|
+
if seconds > 0
|
20
|
+
s = seconds.to_i > 1 ? "seconds" : "minutes"
|
21
|
+
elapsed_time += ", #{seconds.to_i} #{s}"
|
22
|
+
end
|
23
|
+
else
|
24
|
+
s = seconds.to_i > 1 ? "seconds" : "minutes"
|
25
|
+
elapsed_time = "#{seconds.to_i} #{s}"
|
26
|
+
end
|
27
|
+
|
28
|
+
puts
|
29
|
+
e = ""
|
30
|
+
unless message.blank?
|
31
|
+
message += ". "
|
32
|
+
end
|
33
|
+
e = message + e
|
34
|
+
e += "Elapsed time: #{elapsed_time}"
|
35
|
+
puts e
|
36
|
+
g(e)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
def post_file_to_w3c_validator(file_path, doc_type)
|
2
|
+
query = MultipartPost.build_form_data(
|
3
|
+
:uploaded_file => File.new(file_path, 'r'),
|
4
|
+
:charset => '(detect automatically)',
|
5
|
+
:doctype => doc_type,
|
6
|
+
:group => '1'
|
7
|
+
)
|
8
|
+
|
9
|
+
Net::HTTP.start('validator.w3.org') do |http|
|
10
|
+
http.post2("/check", query, MultipartPost::REQ_HEADER)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid_response?(w3c_response)
|
15
|
+
html = w3c_response.read_body
|
16
|
+
html.include? "[Valid]"
|
17
|
+
end
|
18
|
+
|
19
|
+
def w3c_valid?(file_path)
|
20
|
+
resp = post_file_to_w3c_validator(file_path, 'HTML 4.01 Strict')
|
21
|
+
valid_response?(resp)
|
22
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers #:nodoc:
|
3
|
+
# Provides methods to generate HTML tags programmatically when you can't use
|
4
|
+
# a Builder. By default, they output XHTML compliant tags.
|
5
|
+
module TagHelper
|
6
|
+
include ERB::Util
|
7
|
+
|
8
|
+
BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked).to_set
|
9
|
+
BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map {|a| a.to_sym })
|
10
|
+
|
11
|
+
# Returns an empty HTML tag of type +name+ which by default is XHTML
|
12
|
+
# compliant. Set +open+ to true to create an open tag compatible
|
13
|
+
# with HTML 4.0 and below. Add HTML attributes by passing an attributes
|
14
|
+
# hash to +options+. Set +escape+ to false to disable attribute value
|
15
|
+
# escaping.
|
16
|
+
#
|
17
|
+
# ==== Options
|
18
|
+
# The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
|
19
|
+
# <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
|
20
|
+
# symbols or strings for the attribute names.
|
21
|
+
#
|
22
|
+
# ==== Examples
|
23
|
+
# tag("br")
|
24
|
+
# # => <br />
|
25
|
+
#
|
26
|
+
# tag("br", nil, true)
|
27
|
+
# # => <br>
|
28
|
+
#
|
29
|
+
# tag("input", { :type => 'text', :disabled => true })
|
30
|
+
# # => <input type="text" disabled="disabled" />
|
31
|
+
#
|
32
|
+
# tag("img", { :src => "open & shut.png" })
|
33
|
+
# # => <img src="open & shut.png" />
|
34
|
+
#
|
35
|
+
# tag("img", { :src => "open & shut.png" }, false, false)
|
36
|
+
# # => <img src="open & shut.png" />
|
37
|
+
def tag(name, options = nil, open = false, escape = true)
|
38
|
+
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns an HTML block tag of type +name+ surrounding the +content+. Add
|
42
|
+
# HTML attributes by passing an attributes hash to +options+.
|
43
|
+
# Instead of passing the content as an argument, you can also use a block
|
44
|
+
# in which case, you pass your +options+ as the second parameter.
|
45
|
+
# Set escape to false to disable attribute value escaping.
|
46
|
+
#
|
47
|
+
# ==== Options
|
48
|
+
# The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
|
49
|
+
# <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
|
50
|
+
# symbols or strings for the attribute names.
|
51
|
+
#
|
52
|
+
# ==== Examples
|
53
|
+
# content_tag(:p, "Hello world!")
|
54
|
+
# # => <p>Hello world!</p>
|
55
|
+
# content_tag(:div, content_tag(:p, "Hello world!"), :class => "strong")
|
56
|
+
# # => <div class="strong"><p>Hello world!</p></div>
|
57
|
+
# content_tag("select", options, :multiple => true)
|
58
|
+
# # => <select multiple="multiple">...options...</select>
|
59
|
+
#
|
60
|
+
# <% content_tag :div, :class => "strong" do -%>
|
61
|
+
# Hello world!
|
62
|
+
# <% end -%>
|
63
|
+
# # => <div class="strong">Hello world!</div>
|
64
|
+
def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
|
65
|
+
# if block_given?
|
66
|
+
# options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
|
67
|
+
# content_tag = content_tag_string(name, capture(&block), options, escape)
|
68
|
+
#
|
69
|
+
# if block_called_from_erb?(block)
|
70
|
+
# concat(content_tag)
|
71
|
+
# else
|
72
|
+
# content_tag
|
73
|
+
# end
|
74
|
+
# else
|
75
|
+
content_tag_string(name, content_or_options_with_block, options, escape)
|
76
|
+
# end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns a CDATA section with the given +content+. CDATA sections
|
80
|
+
# are used to escape blocks of text containing characters which would
|
81
|
+
# otherwise be recognized as markup. CDATA sections begin with the string
|
82
|
+
# <tt><![CDATA[</tt> and end with (and may not contain) the string <tt>]]></tt>.
|
83
|
+
#
|
84
|
+
# ==== Examples
|
85
|
+
# cdata_section("<hello world>")
|
86
|
+
# # => <![CDATA[<hello world>]]>
|
87
|
+
#
|
88
|
+
# cdata_section(File.read("hello_world.txt"))
|
89
|
+
# # => <![CDATA[<hello from a text file]]>
|
90
|
+
def cdata_section(content)
|
91
|
+
"<![CDATA[#{content}]]>"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns an escaped version of +html+ without affecting existing escaped entities.
|
95
|
+
#
|
96
|
+
# ==== Examples
|
97
|
+
# escape_once("1 > 2 & 3")
|
98
|
+
# # => "1 < 2 & 3"
|
99
|
+
#
|
100
|
+
# escape_once("<< Accept & Checkout")
|
101
|
+
# # => "<< Accept & Checkout"
|
102
|
+
def escape_once(html)
|
103
|
+
html.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
|
108
|
+
|
109
|
+
if RUBY_VERSION < '1.9.0'
|
110
|
+
# Check whether we're called from an erb template.
|
111
|
+
# We'd return a string in any other case, but erb <%= ... %>
|
112
|
+
# can't take an <% end %> later on, so we have to use <% ... %>
|
113
|
+
# and implicitly concat.
|
114
|
+
def block_called_from_erb?(block)
|
115
|
+
block && eval(BLOCK_CALLED_FROM_ERB, block)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
def block_called_from_erb?(block)
|
119
|
+
block && eval(BLOCK_CALLED_FROM_ERB, block.binding)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def content_tag_string(name, content, options, escape = true)
|
124
|
+
tag_options = tag_options(options, escape) if options
|
125
|
+
"<#{name}#{tag_options}>#{content}</#{name}>"
|
126
|
+
end
|
127
|
+
|
128
|
+
def tag_options(options, escape = true)
|
129
|
+
unless options.blank?
|
130
|
+
attrs = []
|
131
|
+
if escape
|
132
|
+
options.each_pair do |key, value|
|
133
|
+
if BOOLEAN_ATTRIBUTES.include?(key)
|
134
|
+
attrs << %(#{key}="#{key}") if value
|
135
|
+
else
|
136
|
+
attrs << %(#{key}="#{escape_once(value)}") if !value.nil?
|
137
|
+
end
|
138
|
+
end
|
139
|
+
else
|
140
|
+
attrs = options.map { |key, value| %(#{key}="#{value}") }
|
141
|
+
end
|
142
|
+
" #{attrs.sort * ' '}" unless attrs.empty?
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|