ymdp 0.0.3
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/.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
|