Contenu connexe Similaire à The Hidden Power of HTMLBars (or, Scope in Ember.js Templates) (20) Plus de Matthew Beale (15) The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)21. EntityScope + Rules + Label
cold beer
cold beers
are served in NYC
“chips”
thin, flat, and fried
slices of potato
28. “In languages with dynamic
scope the name resolution
depends upon the program state
when the name is encountered
which is determined by the
execution context or calling
context.”
Wikipedia
29. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name;
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
30. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6 # show_name: Crisp
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
31. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name;
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
32. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name;
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
33. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
34. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
35. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
36. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp";
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
37. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
38. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
39. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
40. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6 # show_name: Crisp
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
41. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # local_sub: Fry
6 # show_name: Crisp
7 sub local_sub {
8 local $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "local_sub: ", &local_sub(), "n";
18 print "show_name: ", &show_name(), "n";
What context do you
need to understand the
value of $name?
42. “In languages with dynamic
scope the name resolution
depends upon the program state
when the name is encountered
which is determined by the
execution context or calling
context.”
Wikipedia
44. “In languages with lexical scope (also
called static scope), name resolution
depends on the location in the source
code and the lexical context, which is
defined by where the named variable or
function is defined.”
Wikipedia
45. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # my_sub: Crisp
6 # show_name: Crisp
7 sub my_sub {
8 my $name = "Fry";
9 return show_name();
10 }
11
12 sub show_name {
13 return $name;
14 }
15
16 print "$name: $namen";
17 print "my_sub: ", &my_sub(), "n";
18 print "show_name: ", &show_name(), "n";
46. 1 #!/usr/bin/perl -w
2 use strict;
3
4 our $name; # $name: Crisp
5 $name = "Crisp"; # my_sub: Fry
6 # show_name: Crisp
7 sub my_sub {
8 my $name = "Fry";
9 return show_name($name);
10 }
11
12 sub show_name {
13 return shift || $name;
14 }
15
16 print "$name: $namen";
17 print "my_sub: ", &my_sub(), "n";
18 print "show_name: ", &show_name(), "n";
47. “In languages with lexical scope (also
called static scope), name resolution
depends on the location in the source
code and the lexical context, which is
defined by where the named variable or
function is defined.”
Wikipedia
48. Benefits of Static Scope
1. Possible to optimize at compile time
2. Easier for developers to read
3. JavaScript and pretty much all
languages use it
49. 1 {{! app/templates/index.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#view 'localized-menu' model}}
5 <li>{{name}}: {{model.price}}</li>
6 {{/view}}
7 </ul>
Ember 1.x
50. 1 {{! app/templates/index.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#view 'localized-menu' model}}
5 <li>{{name}}: {{model.price}}</li>
6 {{/view}}
7 </ul>
Ember 1.x
• Index controller
• Index controller model
• New context from
localized-menu
• Helper
Dynamic
51. 1 {{! app/templates/index.hbs }}
2 <h2>{{name}} Menu</h2>
3 <ul>
4 {{#view 'localized-menu' model}}
5 <li>{{name}}: {{model.price}}</li>
6 {{/view}}
7 </ul>
Ember 1.x Ember 2.x
1 {{! app/templates/index.hbs }}
2 <h2>{{model.name}} Menu</h2>
3 <ul>
4 {{#each model.snacks as |packet|}}
5 <li>{{packet.name}}: {{packet.price}}</li>
6 {{/each}}
7 </ul>
52. 1 {{! app/templates/index.hbs }}
2 <h2>{{model.name}} Menu</h2>
3 <ul>
4 {{#each model.snacks as |packet|}}
5 <li>{{packet.name}}: {{packet.price}}</li>
6 {{/each}}
7 </ul>
Ember 2.x
• Property on packet
• Helper
Static
53. 1 {{! app/templates/index.hbs }}
2 <h2>{{model.name}} Menu</h2>
3 <ul>
4 {{#each model.snacks as |packet|}}
5 <li>{{packet.name}}: {{packet.price}}</li>
6 {{/each}}
7 </ul>
Ember 2.x
• Property on packet
• Helper
Static
54. 1 {{! app/templates/index.hbs }}
2 <h2>{{model.name}} Menu</h2>
3 <ul>
4 {{#each model.snacks as |packet|}}
5 <li>{{packet.name}}: {{packet.price}}</li>
6 {{/each}}
7 </ul>
1 function buildIndex(model) {
2 let html = `<h2>${model.name} Menu</h2>`;
3 html += '<ul>';
4 model.snacks.forEach(packet => {
5 html += `<li>
6 ${packet.name}: ${packet.price}
7 </li>`;
8 });
9 html += '</ul>';
10 return html;
11 }
Ember 2.x
55. Creating a template system with static
scoping is an intentional goal of
HTMLBars/Glimmer, and directs the
underlying architecture.
58. Closures
1 function generateSayName() {
2 let name = 'Chips';
3 return function() {
4 alert(name);
5 };
6 }
7
8 var sayName = generateSayName();
9
10 console.log(sayName()); // alerts: Chips
59. 1 function generateSayName() {
2 let name = 'Chips';
3 return function() {
4 alert(name);
5 };
6 }
7
8 var sayName = generateSayName();
9
10 console.log(sayName()); // alerts: Chips
Closures
60. Ember Actions as Closures
1 {{#with (action 'alert' name) as |sayName|}}
2 <button {{action sayName}}>Say the name!</button>
3 {{/with}}
61. Ember Actions as Closures
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (action 'alert' name)}}
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name name='Chip' as |sayName|}}
3 <button {{action sayName}}>Say the name!</button>
4 {{/generate-say-name}}
62. Ember Actions as Closures
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (hash
3 sayBritish=(action 'alert' 'Crisp')
4 sayAmerican=(action 'alert' 'Chip')
5 )}}
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name as |ux|}}
3 <button {{action ux.sayBritish}}>Say the name!</button>
4 {{/generate-say-name}}
64. Ember Components as Closures
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the name!{{/ux.sayBritish}}
4 {{/generate-say-name}}
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-name-button' name='Crisp')
4 sayAmerican=(component 'say-name-button' name='Chip')
5 )}}
65. Pods, Local Lookup, and Closures
bit.ly/pods-local-lookup
speakerdeck.com/rwjblue/a-tale-of-two-pods
67. Pods
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 routes/
6 index/
7 template.hbs
1 {{! app/routes/index/template.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}}
4 {{/generate-say-name}}
68. Pods
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 routes/
6 index/
7 template.hbs
1 {{! app/routes/index/template.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}}
4 {{/generate-say-name}}
69. 1 {{! app/components/generate-say-name/template.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-name-button' name='Crisp')
4 sayAmerican=(component 'say-name-button' name='Chip')
5 )}}
Pods
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 routes/
6 index/
7 template.hbs
70. 1 {{! app/components/generate-say-name/template.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-name-button' name='Crisp')
4 sayAmerican=(component 'say-name-button' name='Chip')
5 )}}
Pods
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 routes/
6 index/
7 template.hbs
71. 1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 say-name-button/
6 template.hbs
7 routes/
8 index/
9 template.hbs
1 {{! app/components/generate-say-name/template.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-name-button' name='Crisp')
4 sayAmerican=(component 'say-name-button' name='Chip')
5 )}}
Pods
72. 1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index/
10 template.hbs
1 {{! app/components/generate-say-name/template.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-name-button' name='Crisp')
4 sayAmerican=(component 'say-name-button' name='Chip')
5 )}}
Local Lookup
73. 1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index/
10 template.hbs
1 {{! app/components/generate-say-name/template.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-name-button' name='Crisp')
4 sayAmerican=(component 'say-name-button' name='Chip')
5 )}}
Local Lookup
74. 1 {{! app/routes/index/template.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}}
4 {{/generate-say-name}}
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index/
10 template.hbs
Local Lookup
75. 1 {{! app/routes/index/template.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}}
4 {{/generate-say-name}}
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index/
10 template.hbs
Local Lookup
76. 1 {{! .../say-name-button/template.hbs }}
2 <button {{action 'alert' name}}>{{yield}}</button>
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index/
10 template.hbs
Local Lookup
77. 1 {{! .../say-name-button/template.hbs }}
2 <button {{action 'alert' name}}>{{yield}}</button>
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index/
10 template.hbs
Local Lookup
78. 1 {{! app/routes/index/template.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{#ux.sayBritish}}Say the Name{{/ux.sayBritish}}
4 {{/generate-say-name}}
1 app/
2 components/
3 generate-say-name/
4 template.hbs
5 components/
6 say-name-button/
7 template.hbs
8 routes/
9 index/
10 template.hbs
Local Lookup
81. Partial Application
1 function generateSayName() {
2 let name = 'Chips';
3 return function(honorific) {
4 alert(`${honorific} ${name}`);
5 };
6 }
7
8 var sayName = generateSayName();
9
10 console.log(sayName('Mr.')); // logs: Mr. Chips
82. 1 function generateSayName() {
2 let name = 'Chips';
3 return function(honorific) {
4 alert(`${honorific} ${name}`);
5 };
6 }
7
8 var sayName = generateSayName();
9
10 console.log(sayName('Mr.')); // logs: Mr. Chips
Partial Application
83. 1 function generateSayName() {
2 let name = 'Chips';
3 return function(honorific) {
4 alert(`${honorific} ${name}`);
5 };
6 }
7
8 var sayName = generateSayName();
9
10 console.log(sayName('Mr.')); // logs: Mr. Chips
Partial Application
84. Ember Actions with Partial Application
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name as |sayName|}}
3 <button {{action sayName 'Mr.'}}>Say the name!</button>
4 {{/generate-say-name}}
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (action 'alert' 'Crisps')}}
85. Ember Actions with Partial Application
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name as |sayName|}}
3 <button {{action sayName 'Mr.'}}>Say the name!</button>
4 {{/generate-say-name}}
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (action 'alert' 'Crisps')}}
1 actions: {
2 alert(name, honorific) {
3 console.log(`${honorific} ${name}`);
4 }
5 }
86. Ember Components with Partial Application
1 {{! app/templates/components/generate-say-name.hbs }}
2 {{yield (hash
3 sayBritish=(component 'say-button-name' honorific='MP')
4 sayAmerican=(component 'say-button-name' honorific='Rep')
5 )}}
1 {{! app/templates/index.hbs }}
2 {{#generate-say-name as |ux|}}
3 {{ux.sayBritish name='Chips'}}
4 {{ux.sayAmerican honorific='Mr.' name='Fry'}}
5 {{/generate-say-name}}
1 {{! app/templates/components/say-button-name.hbs }}
2 <button {{action 'alert' name honorific}}>Say the Name</button>
87. Tools for Static Scope
Recursion?!
emberjs.jsbin.com/fubutusejo/1/edit?html,js,output