www_app 1.3.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/README.md +42 -24
  4. data/VERSION +1 -1
  5. data/bin/www_app +15 -4
  6. data/lib/public/vendor/hogan-3.0.2.min.js +5 -0
  7. data/lib/public/vendor/instruct_instruct_instruct.js +247 -0
  8. data/lib/public/vendor/jquery-2.1.3.min.js +4 -0
  9. data/lib/public/vendor/lodash.min.js +89 -0
  10. data/lib/public/www_app.js +885 -625
  11. data/lib/www_app/CSS.rb +310 -0
  12. data/lib/www_app/HTML.rb +219 -0
  13. data/lib/www_app/JavaScript.rb +51 -0
  14. data/lib/www_app/TO.rb +897 -0
  15. data/lib/www_app.rb +324 -945
  16. data/playground/config.ru +102 -0
  17. data/specs/client-side/index.html +1 -1
  18. data/specs/client-side/index.js +31 -379
  19. data/specs/lib/config.ru +60 -31
  20. data/specs/lib/helpers.rb +24 -2
  21. data/specs/server-side/0000-new.rb +1 -1
  22. data/specs/server-side/0001-underscore-double.rb +38 -0
  23. data/specs/server-side/0001-underscore.rb +73 -0
  24. data/specs/server-side/0010-attrs.rb +3 -4
  25. data/specs/server-side/0011-id.rb +5 -5
  26. data/specs/server-side/0020-tag.rb +2 -2
  27. data/specs/server-side/0020-tag_content.rb +1 -1
  28. data/specs/server-side/0021-body.rb +1 -1
  29. data/specs/server-side/0021-script.rb +66 -20
  30. data/specs/server-side/{0021-page_title.rb → 0021-title.rb} +5 -3
  31. data/specs/server-side/0030-mustache.rb +27 -20
  32. data/specs/server-side/0030-style.rb +64 -21
  33. data/specs/server-side/0040-css.rb +4 -4
  34. data/specs/server-side/0041-pseudo.rb +55 -0
  35. data/specs/server-side/0042-slash.rb +20 -0
  36. data/specs/server-side/0060-text.rb +26 -0
  37. metadata +18 -13
  38. data/lib/public/jquery-2.1.1.js +0 -4
  39. data/lib/public/underscore-1.7.0.js +0 -6
  40. data/lib/public/underscore-min.map +0 -1
  41. data/lib/public/underscore.string-2.3.0.js +0 -1
  42. data/lib/www_app/Clean.rb +0 -169
  43. data/lib/www_app/dsl.rb +0 -86
  44. data/lib/www_app/source.rb +0 -53
  45. data/specs/server-side/0050-on.rb +0 -64
  46. data/specs/server-side/0060-string.rb +0 -32
  47. /data/lib/public/{jquery.serialize-object.min.js → vendor/jquery.serialize-object.min.js} +0 -0
data/specs/lib/config.ru CHANGED
@@ -3,46 +3,75 @@
3
3
  require 'cuba'
4
4
  require 'da99_rack_protect'
5
5
  require 'multi_json'
6
+ require 'www_app'
6
7
 
7
- Cuba.use Da99_Rack_Protect.config { |c|
8
- c.config :host, [:localhost, 'www_app.com']
9
- }
8
+ PATH = File.expand_path(File.dirname(__FILE__) + '../../..')
10
9
 
11
- Cuba.use Rack::ShowExceptions
10
+ Rack::Mime::MIME_TYPES.merge!({".map" => "application/json"})
12
11
 
13
- Cuba.use(Class.new {
14
- def initialize app
15
- @app = app
16
- end
12
+ Cuba.use Da99_Rack_Protect do |c|
13
+ c.config :host, :localhost if ENV['IS_DEV']
14
+ end
15
+
16
+ Cuba.use Rack::ShowExceptions
17
17
 
18
- def call env
19
- results = @app.call(env)
20
- if results.first == 404
21
- if env['PATH_INFO'] == '/'
22
- return [
23
- 200,
24
- {"Content-Type" => "text/html"},
25
- [File.read("./specs/client-side/index.html").gsub("{token}", env['rack.session']['csrf'])]
26
- ]
27
- end
28
-
29
- [
30
- Rack::Directory.new(File.expand_path('./specs/lib')),
31
- Rack::Directory.new(File.expand_path('./specs/client-side')),
32
- Rack::Directory.new(File.expand_path('./lib/public'))
33
- ].detect { |r|
34
- status, headers, body = r.call(env)
35
- return [status, headers, body] if status != 404
36
- false
18
+ # Cuba.use(Class.new {
19
+ # def initialize app
20
+ # @app = app
21
+ # end
22
+
23
+ # def call env
24
+ # results = @app.call(env)
25
+ # if results.first == 404
26
+ # if env['PATH_INFO'] == '/old'
27
+ # return [
28
+ # 200,
29
+ # {"Content-Type" => "text/html"},
30
+ # [File.read("./specs/client-side/index.html").gsub("{token}", env['rack.session']['csrf'])]
31
+ # ]
32
+ # end
33
+
34
+ # [
35
+ # Rack::Directory.new(File.expand_path('./specs/lib')),
36
+ # Rack::Directory.new(File.expand_path('./specs/client-side')),
37
+ # Rack::Directory.new(File.expand_path('./lib/public'))
38
+ # ].detect { |r|
39
+ # status, headers, body = r.call(env)
40
+ # return [status, headers, body] if status != 404
41
+ # false
42
+ # }
43
+ # end
44
+
45
+ # results
46
+ # end
47
+ # })
48
+
49
+
50
+ PAGES = {
51
+ :root => WWW_App.new {
52
+ title { 'hello' }
53
+ div {
54
+ _.^(:happy) {
55
+ border '1px dashed red'
56
+ }
57
+ on(:click) {
58
+ add_class :happy
59
+ }
60
+ "Almost done."
37
61
  }
38
- end
62
+ }
63
+ }
39
64
 
40
- results
41
- end
42
- })
65
+ Cuba.use Rack::Static, :urls=>["/www_app-#{File.read(PATH + '/VERSION').strip}"], :root=>'Public'
43
66
 
44
67
  Cuba.define do
45
68
 
69
+ on get do
70
+ on root do
71
+ res.write PAGES[:root].to_html
72
+ end
73
+ end
74
+
46
75
  on post do
47
76
  data = (req.env["rack.request.form_hash"]).dup
48
77
  data.delete('authenticity_token')
data/specs/lib/helpers.rb CHANGED
@@ -21,6 +21,10 @@ def norm ugly
21
21
  join("\n")
22
22
  end
23
23
 
24
+ def norm_wo_lines str
25
+ str.split("\n").map(&:strip).join ""
26
+ end
27
+
24
28
  def strip_each_line str
25
29
  str.split("\n").map(&:strip).join "\n"
26
30
  end
@@ -40,6 +44,10 @@ def script html
40
44
  get_content 'script', html
41
45
  end
42
46
 
47
+ def script_srcs str
48
+ str.scan(%r@<script src="([^"]+)"></script>@).flatten
49
+ end
50
+
43
51
  def body html
44
52
  get_content 'body', html
45
53
  end
@@ -81,13 +89,25 @@ end
81
89
  module Bacon
82
90
  class Context
83
91
 
92
+ #
93
+ # NOTE: I know this is a lazy hack,
94
+ # but I was short on time.
95
+ #
96
+ alias_method :rr_wo_target_args, :run_requirement
97
+ def run_requirement *args
98
+ @target_args = nil
99
+ rr_wo_target_args(*args) {
100
+ yield if block_given?
101
+ }
102
+ end
103
+
84
104
  def target *args
85
105
  @target_args = args
86
106
  end
87
107
 
88
108
  def actual vals = {}, &blok
89
109
  if !@target_args
90
- return WWW_App.new(&blok).render(vals)
110
+ return WWW_App.new(&blok).to_html(vals)
91
111
  end
92
112
 
93
113
  include_tag = if @target_args.first == :outer
@@ -98,7 +118,7 @@ module Bacon
98
118
  norm_target = norm @target_args.last
99
119
 
100
120
  tag = @target_args.first
101
- html = WWW_App.new(&blok).render(vals)
121
+ html = WWW_App.new(&blok).to_html(vals)
102
122
  section = case
103
123
  when include_tag
104
124
  html[/(<#{tag}[^\>]*>.+<\/#{tag}>)/m] && $1
@@ -118,6 +138,8 @@ module Bacon
118
138
  end
119
139
 
120
140
  norm_actual.should == norm_target
141
+
142
+ @target_args = nil
121
143
  end
122
144
 
123
145
  end # === class Context ===
@@ -7,7 +7,7 @@ describe "it runs" do
7
7
  div {
8
8
  "test"
9
9
  }
10
- }.render.should == "<div>test</div>"
10
+ }.to_html.should == "<div>test</div>"
11
11
  end
12
12
 
13
13
  end # === describe IS_DEV ===
@@ -0,0 +1,38 @@
1
+
2
+ describe :underscore__double do
3
+
4
+ it "lets you combine different elements in a css selector" do
5
+ target :style, %^
6
+ div.bad div {
7
+ color: #mebad;
8
+ }
9
+ ^
10
+
11
+ actual {
12
+ style {
13
+ div.^(:bad).__.div {
14
+ color '#mebad'
15
+ }
16
+ }
17
+ }
18
+ end # === it lets you combine different elements in a css selector
19
+
20
+ it "can be used with :_ in :style: div.__._ { ... }" do
21
+ target :style, %^
22
+ div.outside #main.inner {
23
+ color: #deep;
24
+ }
25
+ ^
26
+
27
+ actual do
28
+ div.id(:main) {
29
+ style {
30
+ div.^(:outside).__._.^(:inner) {
31
+ color '#deep'
32
+ }
33
+ }
34
+ }
35
+ end
36
+ end # === it can be used with :_ in :style: div.__._ { ... }
37
+
38
+ end # === describe :underscore__double
@@ -0,0 +1,73 @@
1
+
2
+ describe :_ do
3
+
4
+ it "let's you add :id to the body" do
5
+ actual = WWW_App.new {
6
+ _.id(:the_body)
7
+ }.to_html
8
+
9
+ actual[/<body[^\<]+/].should == %!<body id="the_body">!
10
+ end # === it lets you add :id to the body
11
+
12
+ it "let's you add a :class to body" do
13
+ actual = WWW_App.new {
14
+ _.^(:sad)
15
+ }.to_html
16
+
17
+ actual[/<body[^\<]+/].should == %!<body class="sad">!
18
+ end # === it lets you add a :class to body
19
+
20
+ it "let's you create a style inside a tag, outside of :style" do
21
+ target :style, <<-EOF
22
+ #main.happy:link {
23
+ color: #happy;
24
+ }
25
+
26
+ #main.sad {
27
+ border: 1px dashed red;
28
+ }
29
+ EOF
30
+
31
+ actual do
32
+ div.id(:main) {
33
+ _.^(:happy)._link { color '#happy' }
34
+ _.^(:sad) { border '1px dashed red' }
35
+ }
36
+ end
37
+ end # === it let's you create a style inside a tag, outside of :style
38
+
39
+ it "refers to the :body when used inside a parent-less :style" do
40
+ target :style, %!
41
+ body {
42
+ color: #abc;
43
+ }
44
+ !
45
+
46
+ actual do
47
+ style {
48
+ _ {
49
+ color '#abc'
50
+ }
51
+ }
52
+ end
53
+ end # === it refers to the :body when used inside a parent-less :style
54
+
55
+ it "can be used with double-underscore: _.__div" do
56
+ target :style, %^
57
+ #main.sad div.happy {
58
+ color: #confused;
59
+ }
60
+ ^
61
+
62
+ actual do
63
+ div.id(:main).^(:sad) {
64
+ style {
65
+ _.__.div.^(:happy) {
66
+ color '#confused'
67
+ }
68
+ }
69
+ }
70
+ end
71
+ end # === it can be used with double-underscore: _.__div
72
+
73
+ end # === describe :_
@@ -1,15 +1,14 @@
1
1
 
2
2
  describe "all attrs" do
3
3
 
4
- it "raises a RuntimeError if tag has an unknown attribute" do
4
+ it "raises a RuntimeError if tag has an invalid attribute" do
5
5
  should.raise(RuntimeError) {
6
6
  actual {
7
- a.href('/href') {
8
- tag![:attrs][:hi] = 'hiya'
7
+ a.href('/href').src('file') {
9
8
  "here"
10
9
  }
11
10
  }
12
- }.message.should.match /Unknown attr: :hi/
11
+ }.message.should.match /:src not allowed to be set here/
13
12
  end
14
13
 
15
14
  it "escapes attributes" do
@@ -1,12 +1,12 @@
1
1
 
2
2
 
3
3
 
4
- describe :* do
4
+ describe :id do
5
5
 
6
6
  it "raises Invalid if id has invalid chars" do
7
7
  should.raise(Escape_Escape_Escape::Invalid) {
8
8
  actual do
9
- div.*('a<&a') { 'hello' }
9
+ div.id('a<&a') { 'hello' }
10
10
  end
11
11
  }.message.should.match /a<&a/
12
12
  end
@@ -14,8 +14,8 @@ describe :* do
14
14
  it "raises HTML_ID_Duplicate if id is used more than once" do
15
15
  should.raise(WWW_App::HTML_ID_Duplicate) {
16
16
  actual do
17
- div.*(:my_id) { '1' }
18
- div.*(:my_id) { '2' }
17
+ div.id(:my_id) { '1' }
18
+ div.id(:my_id) { '2' }
19
19
  end
20
20
  }.message.should.match /my_id/
21
21
  end
@@ -29,7 +29,7 @@ describe :* do
29
29
  target '<a id="warning" href="&#47;there">There</a>'
30
30
 
31
31
  actual do
32
- a.*(:warning).href('/there') { "There" }
32
+ a.id(:warning).href('/there') { "There" }
33
33
  end
34
34
  end
35
35
 
@@ -4,7 +4,7 @@ describe :tag do
4
4
  it "raises Invalid if tag starts w/ a number" do
5
5
  should.raise(Escape_Escape_Escape::Invalid) {
6
6
  actual do
7
- div.*('0a') { 'hello' }
7
+ div.id('0a') { 'hello' }
8
8
  end
9
9
  }.message.should.match /0a/
10
10
  end
@@ -12,7 +12,7 @@ describe :tag do
12
12
  it "raises Invalid if tag is unknown: e.g. :footers" do
13
13
  should.raise(StandardError) {
14
14
  actual do
15
- tag(:footers) { 'bye' }
15
+ footers { 'bye' }
16
16
  end
17
17
  }.message.should.match /footers/
18
18
  end
@@ -1,5 +1,5 @@
1
1
 
2
- describe "HTML contents" do
2
+ describe 'tag content' do
3
3
 
4
4
  it "uses last String value as content" do
5
5
  target %^<p>Hello</p>^
@@ -1,7 +1,7 @@
1
1
 
2
2
  describe "body with inner style" do
3
3
 
4
- it "uses 'body' instead of id" do
4
+ it "adds styles to page as: body { ... }" do
5
5
  target :style, %^
6
6
  body {
7
7
  border-width: 3px;
@@ -4,41 +4,87 @@ describe :script do
4
4
  it "raises Invalid_Relative_HREF if :src is not relative" do
5
5
  should.raise(Escape_Escape_Escape::Invalid_Relative_HREF) {
6
6
  actual do
7
- script.src('http://www.example.org/file.js')./
7
+ script('http://www.example.org/file.js')
8
8
  end
9
9
  }.message.should.match /example\.org/
10
10
  end
11
11
 
12
+ it "puts custom script files w/ :src at the after vendor files and www_app.js" do
13
+ actual = WWW_App.new {
14
+ p { 'paragraph' }
15
+ script 'my_script.js'
16
+ }.to_html
17
+
18
+ script_srcs(actual).last.should == 'my_script.js'
19
+ end # === it puts custom script files w/ :src at the after vendor files and www_app.js
20
+
12
21
  it "allows a relative :src" do
13
- target %^<script src="&#47;file.js"></script>^
14
- actual {
15
- script.src('/file.js')./
16
- }
22
+ actual = WWW_App.new {
23
+ script('/file.js')
24
+ }.to_html
25
+
26
+ script_srcs(actual).last.should == %^&#47;file.js^
17
27
  end
18
28
 
19
29
  it "escapes slashes in attr :src" do
20
- target %^<script src="&#47;dir&#47;file.js"></script>^
21
- actual {
22
- script.src('/dir/file.js')./
23
- }
24
- end
30
+ actual = WWW_App.new {
31
+ script('/dir/file.js')
32
+ }.to_html
25
33
 
26
- it "does not allow vars in :script :src attribute" do
27
- target :body, <<-EOF
28
- <script src="help"></script>
29
- EOF
34
+ script_srcs(actual).last.should == %^&#47;dir&#47;file.js^
35
+ end
30
36
 
31
- actual do
32
- script.src(:help)
33
- end
37
+ it "allowed to have a :class attribute" do
38
+ WWW_App.new {
39
+ script.^(:append) do
40
+ div {}
41
+ end
42
+ }.to_html.should.match /<script type="text\/mustache" class="append"/
34
43
  end
35
44
 
36
- it "ignores text for :script block" do
37
- target %^<script src="&#47;hello.js"></script>^
45
+ it "renders :type when given a block" do
46
+ target %^<script type="text/text">hello</script>^
38
47
  actual {
39
- script.src('/hello.js') { 'hello' }
48
+ script('text/text') { 'hello' }
40
49
  }
41
50
  end
42
51
 
52
+ it "includes client-side script files" do
53
+ actual = WWW_App.new {
54
+ div { }
55
+ script 'my.js'
56
+ }.to_html
57
+
58
+ targets = (
59
+ Dir.glob('lib/public/**/*.js').map { |f|
60
+ href = "/www_app-#{File.read('VERSION').strip}/#{f}".sub('/lib/public', '')
61
+ Escape_Escape_Escape.relative_href href
62
+ } + ['my.js']
63
+ )
64
+
65
+ script_srcs(actual).sort.should == targets.sort
66
+ end # === it includes client-side script files
67
+
68
+ it "is rendered inside a full document" do
69
+ actual = WWW_App.new {
70
+ div { }
71
+ script 'my.js'
72
+ }.to_html
73
+
74
+ actual['<body>'].should == '<body>'
75
+ end
76
+
77
+ it "allows rendering of child elements" do
78
+ target :body, <<-EOF
79
+ <script type="text/mustache">
80
+ <div>!{ html.hello }!</div>
81
+ </script>
82
+ EOF
83
+ actual do
84
+ script 'text/mustache' do
85
+ div { :hello }
86
+ end
87
+ end
88
+ end # === it allows rendering of child elements
43
89
 
44
90
  end # === describe :JS ===
@@ -2,9 +2,11 @@
2
2
  describe "page_title" do
3
3
 
4
4
  it "creates only one :title tag" do
5
- WWW_App.new {
6
- page_title { 'yo' }
7
- }.render.scan(/<title>[^>]+<\/title>/).
5
+ html = WWW_App.new {
6
+ title { 'yo' }
7
+ }.to_html
8
+
9
+ html.scan(/<title>[^>]+<\/title>/).
8
10
  should == ['<title>yo</title>']
9
11
  end # === it creates on :title tag
10
12
 
@@ -56,45 +56,52 @@ describe :mustache do
56
56
  end
57
57
 
58
58
  it "escapes html in nested values" do
59
- target <<-EOF
60
- <div id="my_box"><span>&amp; hello 1</span>
61
- <span>&amp;&amp; hello 2</span></div>
62
- EOF
63
-
64
- actual(:hello=>{:msg=>'& hello 1', :goodbye=>nil}) {
65
- div.*(:my_box) {
59
+ actual = WWW_App.new() {
60
+ div.id(:my_box) {
66
61
  render_if(:hello) {
67
62
  span { :msg }
68
- render_unless(:goodbye) { span { '&& hello 2' } }
63
+ render_unless(:goodbye) {
64
+ span { '&& hello 2' }
65
+ }
69
66
  }
70
67
  }
71
- }
68
+ }.to_html(:hello=>{:msg=>'& hello 1', :goodbye=>nil})
69
+
70
+ target = <<-EOF
71
+ <div id="my_box"><span>&amp; hello 1</span>
72
+ <span>&amp;&amp; hello 2</span></div>
73
+ EOF
74
+
75
+ norm_wo_lines(actual).should == norm_wo_lines(target)
72
76
  end
73
77
 
74
78
  it "escapes :href in nested values" do
75
- target %^<div><div><a href="&#47;hello">hello</a></div></div>^
76
- actual(o: {url: '/hello', msg: 'hello'}) {
79
+ actual = WWW_App.new {
77
80
  div {
78
81
  render_if(:o) {
79
82
  div { a.href(:url) { :msg } }
80
83
  }
81
84
  }
82
- }
85
+ }.to_html(o: {url: '/hello', msg: 'hello'})
86
+ target = %^<div><div><a href="&#47;hello">hello</a></div></div>^
87
+ norm_wo_lines(actual).should == norm_wo_lines(target)
83
88
  end
84
89
 
85
90
  it "does not allow vars to be used in form :action" do
86
- target %^<form action="url"><input type="hidden" name="auth_token" value="hello" /></form>^
91
+ should.raise(Escape_Escape_Escape::Invalid_Type) {
92
+ actual :url=>'not allowed', :auth_token => 'hello' do
93
+ form.action(:url) {}
94
+ end
95
+ }.message.should.match /:url/
87
96
 
88
- actual :auth_token => 'hello' do
89
- form.action(:url) {}
90
- end
91
97
  end
92
98
 
93
99
  it "does not allow vars to be used in :link :href" do
94
- target %^<link href="hello" />^
95
- actual {
96
- link.href(:hello)./
97
- }
100
+ should.raise(Escape_Escape_Escape::Invalid_Type) {
101
+ actual(:hello=>'not_allowed') {
102
+ link.href(:hello)./
103
+ }
104
+ }.message.should.match /:hello/
98
105
  end
99
106
 
100
107
  it "raises ContextMiss if encounters unescaped value" do