From 58aead81b74b6685cefb118bad15caa5ee15a43a Mon Sep 17 00:00:00 2001 From: cibernox Date: Mon, 14 Nov 2016 16:48:36 +0000 Subject: [PATCH 1/5] Contextual helpers RFC --- text/0000-contextual-helpers.md | 186 ++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 text/0000-contextual-helpers.md diff --git a/text/0000-contextual-helpers.md b/text/0000-contextual-helpers.md new file mode 100644 index 0000000000..8460b5d5c1 --- /dev/null +++ b/text/0000-contextual-helpers.md @@ -0,0 +1,186 @@ +- Start Date: 2016-10-14 +- RFC PR: (leave this empty) +- Ember Issue: (leave this empty) + +# Summary + +The goal of this RFC is to allow for better helper composition by allowing helpers +to be invoked and curried in a similar way as how actions and components can be dynamically +be invoked now. + +# Motivation + +Since Ember 2.3, released in January of 2016, the framework has enjoyed a feature commonly +referred a **contextual components** that allows components to be dynamically invoked by name +and also to be wrapped along with arguments and passed as regular values to later on be invoked. + +Examples from the blog post of the 2.3 release: + +```hbs +{{#alert-box as |box|}} + Danger, Will Robinson! +
+ {{#box.close-button}} + It's just a plain old meteorite. + {{/box.close-button}} +
+{{/alert-box}} +``` + +This features allows to create very nice domain-specific APIs in components. Some examples +of this in the wild can be found in [ember-basic-dropdown](https://github.com/cibernox/ember-basic-dropdown), +[ember-form-for](https://github.com/martndemus/ember-form-for) and [ember-form-for](https://github.com/cibernox/ember-power-calendar). + +However, the same feature is not yet supported for helpers and it would be equally useful for +exposing helpers with prepopulated arguments or options to provide better APIs. + + +# Detailed design + +The design of this feature should be as similar to the **contextual components** feature as +possible so users feel confortable with it immediatly. + +Therefore the natural option would be the creation of a `helper` helper that depending on the context +invokes a helper by its name or creates a closure helper to pass it around. + +However there is an ambiguity with this approach that is not present with components. I'm going to explose +the problem first since it's going to drive the entire design of the feature. + +```hbs +{{my-component format-date=(helper "moment-format")}} +``` + +In the example above it's not clear the intention of the developer. The developer might be +trying: + +- Immediatly evaluate the helper and pass the value of its evaludation to the component +- Create a closure helper and pass it to the component, so it can be called later. + +Note that this ambiguity is not present when the `helper` helper is called in the +context of html. By example + +```hbs +My name is {{helper 'capitalize-str' user.name}} + +``` + +In those examples above the only option can be immediatly evaluate. + +In the proposed syntax of glimmer-components the ambiguity doesn't exists when passing attributes +but it does when passing properties: + +```hbs + + +``` + +How is this problem solved? + +There is three possible options + +#### Use a different helper for creating closure helpers and to evaluate helpers + +This is the most evident aternative. To remove the ambiguity, there is two different helpers for the two different +features. + +Ideas include `helper` to create the closure helper and `invoke-helper` to invoke it. +Another possible names borrowed from ruby conventions can be `helper` (closure creator) and `helper!` (invocation). + + +Examples: + +```hbs +My name is {{invoke-helper 'capitalize-str' user.name}} + +My name is {{helper 'capitalize-str' user.name}} + + +{{my-component format-date=(helper "moment-format")}} +{{my-component format-date=(invoke-helper "moment-format")}} +``` + +#### Wrap in parameters to force imediate execution + +This leaves ember with only on `helper` helper that by default is a closure creator but when wrapped in an extra pair or parens +behavies like `invoke-helper` did on the previous section. + +Examples: + +```hbs +My name is {{(helper 'capitalize-str' user.name)}} + +My name is {{helper 'capitalize-str' user.name}} + + +{{my-component format-date=(helper "moment-format")}} +{{my-component format-date=((helper "moment-format"))}} +``` + +This is dryer but probably too subtle, and double paranthesis have been historycally a syntax error in Ember. + +#### Use an option to disambiguate + +This is not very different from the first strategy but instead of using a different helper it passes a special option +to change the default behaviour. + +For the next example the default behaviour will be immediate-execition helper and the opt-in will be creating a closure +helper (`closure=true`). + + +```hbs +My name is {{helper 'capitalize-str' user.name}} + +My name is {{helper 'capitalize-str' user.name closure=true}} + + +{{my-component format-date=(helper "moment-format" closure=true)}} +{{my-component format-date=(helper "moment-format"))}} +``` + +#### Static code or runtime analysis? + +I'm unsure if this is feasible, but with glimmer's cross-template optimizations it might be possible to +detect how the passed component is used in the context where it is passed and the desambiguation is done +by the engine. + +Examples: + +```hbs +My name is {{helper 'capitalize-str' user.name}} + + +{{my-component-a format-date=(helper "moment-format")}} +{{my-component-b format-date=(helper "moment-format")}} +{{yield (hash format-date=(helper "moment-format"))}} + + +My name is {{format-date}} + + +My name is {{helper format-date date locale="fr"}} + + +{{#my-yielder as |api|}} + {{api.format-date}} +{{/my-yielder}} +``` + +# How We Teach This + +Given the parallelism with closure components it's not going to be hard to teach. It will follow the usual +process of documentation in the API and in the guides. + +# Drawbacks + +Every dynamic feature has some runtime cost. I've heard about some proposals to limit the possible +components that the `{{component}}` helper can invoke so the dependency resolution can be done statically. +Whatever solution is designed for the component helper must also be take into consideration for the `{{helper`}} helper. + +# Alternatives + +The RFC already discusses the alterniative paths since they are the main subject of the proposal. + +# Unresolved questions + +Optional, but suggested for first drafts. What parts of the design are still +TBD? \ No newline at end of file From 0a53216e8ca6cbf518af4a3cce3040eebcd60976 Mon Sep 17 00:00:00 2001 From: cibernox Date: Mon, 14 Nov 2016 17:00:12 +0000 Subject: [PATCH 2/5] Remove one alternative --- text/0000-contextual-helpers.md | 34 ++++----------------------------- 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/text/0000-contextual-helpers.md b/text/0000-contextual-helpers.md index 8460b5d5c1..7d5b581942 100644 --- a/text/0000-contextual-helpers.md +++ b/text/0000-contextual-helpers.md @@ -80,7 +80,7 @@ There is three possible options #### Use a different helper for creating closure helpers and to evaluate helpers -This is the most evident aternative. To remove the ambiguity, there is two different helpers for the two different +**This is the most evident aternative and the one I prefer**. To remove the ambiguity, there is two different helpers for the two different features. Ideas include `helper` to create the closure helper and `invoke-helper` to invoke it. @@ -99,6 +99,8 @@ Examples: {{my-component format-date=(invoke-helper "moment-format")}} ``` +The obvious drawback of this alternative is having two new keywords in ember instead of only one. + #### Wrap in parameters to force imediate execution This leaves ember with only on `helper` helper that by default is a closure creator but when wrapped in an extra pair or parens @@ -137,34 +139,6 @@ helper (`closure=true`). {{my-component format-date=(helper "moment-format"))}} ``` -#### Static code or runtime analysis? - -I'm unsure if this is feasible, but with glimmer's cross-template optimizations it might be possible to -detect how the passed component is used in the context where it is passed and the desambiguation is done -by the engine. - -Examples: - -```hbs -My name is {{helper 'capitalize-str' user.name}} - - -{{my-component-a format-date=(helper "moment-format")}} -{{my-component-b format-date=(helper "moment-format")}} -{{yield (hash format-date=(helper "moment-format"))}} - - -My name is {{format-date}} - - -My name is {{helper format-date date locale="fr"}} - - -{{#my-yielder as |api|}} - {{api.format-date}} -{{/my-yielder}} -``` - # How We Teach This Given the parallelism with closure components it's not going to be hard to teach. It will follow the usual @@ -174,7 +148,7 @@ process of documentation in the API and in the guides. Every dynamic feature has some runtime cost. I've heard about some proposals to limit the possible components that the `{{component}}` helper can invoke so the dependency resolution can be done statically. -Whatever solution is designed for the component helper must also be take into consideration for the `{{helper`}} helper. +Whatever solution is designed for the component helper must also be take into consideration for the `{{helper}}` helper. # Alternatives From ad06d726e0b9837a6e179013749f0853b0853e52 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Mon, 14 Nov 2016 21:28:43 +0100 Subject: [PATCH 3/5] Update 0000-contextual-helpers.md --- text/0000-contextual-helpers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-contextual-helpers.md b/text/0000-contextual-helpers.md index 7d5b581942..f62f718d64 100644 --- a/text/0000-contextual-helpers.md +++ b/text/0000-contextual-helpers.md @@ -104,7 +104,7 @@ The obvious drawback of this alternative is having two new keywords in ember ins #### Wrap in parameters to force imediate execution This leaves ember with only on `helper` helper that by default is a closure creator but when wrapped in an extra pair or parens -behavies like `invoke-helper` did on the previous section. +behaves like `invoke-helper` did on the previous section. Examples: @@ -157,4 +157,4 @@ The RFC already discusses the alterniative paths since they are the main subject # Unresolved questions Optional, but suggested for first drafts. What parts of the design are still -TBD? \ No newline at end of file +TBD? From 3b3ad9eebd0edd70bdab1827e3cc3d8253adb6b6 Mon Sep 17 00:00:00 2001 From: cibernox Date: Tue, 7 Feb 2017 22:33:36 +0000 Subject: [PATCH 4/5] Small changes --- text/0000-contextual-helpers.md | 62 +++++++-------------------------- 1 file changed, 12 insertions(+), 50 deletions(-) diff --git a/text/0000-contextual-helpers.md b/text/0000-contextual-helpers.md index f62f718d64..f254998852 100644 --- a/text/0000-contextual-helpers.md +++ b/text/0000-contextual-helpers.md @@ -1,16 +1,16 @@ -- Start Date: 2016-10-14 +- Start Date: 2016-02-7 - RFC PR: (leave this empty) - Ember Issue: (leave this empty) # Summary -The goal of this RFC is to allow for better helper composition by allowing helpers +The goal of this RFC is to increase composability oportunities in ember by allowing helpers to be invoked and curried in a similar way as how actions and components can be dynamically be invoked now. # Motivation -Since Ember 2.3, released in January of 2016, the framework has enjoyed a feature commonly +Since Ember 2.3, released over a year ago, the framework has enjoyed a feature commonly referred a **contextual components** that allows components to be dynamically invoked by name and also to be wrapped along with arguments and passed as regular values to later on be invoked. @@ -29,12 +29,11 @@ Examples from the blog post of the 2.3 release: This features allows to create very nice domain-specific APIs in components. Some examples of this in the wild can be found in [ember-basic-dropdown](https://github.com/cibernox/ember-basic-dropdown), -[ember-form-for](https://github.com/martndemus/ember-form-for) and [ember-form-for](https://github.com/cibernox/ember-power-calendar). +[ember-form-for](https://github.com/martndemus/ember-form-for) and [ember-power-calendar](https://github.com/cibernox/ember-power-calendar). However, the same feature is not yet supported for helpers and it would be equally useful for exposing helpers with prepopulated arguments or options to provide better APIs. - # Detailed design The design of this feature should be as similar to the **contextual components** feature as @@ -43,15 +42,15 @@ possible so users feel confortable with it immediatly. Therefore the natural option would be the creation of a `helper` helper that depending on the context invokes a helper by its name or creates a closure helper to pass it around. -However there is an ambiguity with this approach that is not present with components. I'm going to explose +However there is an ambiguity with this approach that is not present with components. I'm going to expose the problem first since it's going to drive the entire design of the feature. ```hbs {{my-component format-date=(helper "moment-format")}} ``` -In the example above it's not clear the intention of the developer. The developer might be -trying: +In the example above it's not clear the intention of the developer. The developer's intention +can be a few things: - Immediatly evaluate the helper and pass the value of its evaludation to the component - Create a closure helper and pass it to the component, so it can be called later. @@ -76,17 +75,13 @@ but it does when passing properties: How is this problem solved? -There is three possible options - #### Use a different helper for creating closure helpers and to evaluate helpers -**This is the most evident aternative and the one I prefer**. To remove the ambiguity, there is two different helpers for the two different -features. +To remove the ambiguity, there is two different keywords for the two different features. Ideas include `helper` to create the closure helper and `invoke-helper` to invoke it. Another possible names borrowed from ruby conventions can be `helper` (closure creator) and `helper!` (invocation). - Examples: ```hbs @@ -101,43 +96,10 @@ Examples: The obvious drawback of this alternative is having two new keywords in ember instead of only one. -#### Wrap in parameters to force imediate execution - -This leaves ember with only on `helper` helper that by default is a closure creator but when wrapped in an extra pair or parens -behaves like `invoke-helper` did on the previous section. - -Examples: - -```hbs -My name is {{(helper 'capitalize-str' user.name)}} - -My name is {{helper 'capitalize-str' user.name}} - - -{{my-component format-date=(helper "moment-format")}} -{{my-component format-date=((helper "moment-format"))}} -``` - -This is dryer but probably too subtle, and double paranthesis have been historycally a syntax error in Ember. - -#### Use an option to disambiguate - -This is not very different from the first strategy but instead of using a different helper it passes a special option -to change the default behaviour. - -For the next example the default behaviour will be immediate-execition helper and the opt-in will be creating a closure -helper (`closure=true`). - - -```hbs -My name is {{helper 'capitalize-str' user.name}} - -My name is {{helper 'capitalize-str' user.name closure=true}} - - -{{my-component format-date=(helper "moment-format" closure=true)}} -{{my-component format-date=(helper "moment-format"))}} -``` +Ideally since the idea of wrapping a component and a helper is very similar, I think that +this keyword should be used for both components and helpers and replace the existing +overloaded `component` keyword. +Perhaps the transition to glimmer-components will open an oportunity window for this. # How We Teach This From dd0c338bf20c89ffc9a483d76309e0df6db0df65 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Wed, 8 Feb 2017 04:07:06 +0000 Subject: [PATCH 5/5] Update 0000-contextual-helpers.md - Fixes typos - Removed references to currently unspecified angle bracket component syntax --- text/0000-contextual-helpers.md | 40 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/text/0000-contextual-helpers.md b/text/0000-contextual-helpers.md index f254998852..30bbc1ef67 100644 --- a/text/0000-contextual-helpers.md +++ b/text/0000-contextual-helpers.md @@ -4,17 +4,17 @@ # Summary -The goal of this RFC is to increase composability oportunities in ember by allowing helpers +The goal of this RFC is to increase composability opportunities in Ember by allowing helpers to be invoked and curried in a similar way as how actions and components can be dynamically be invoked now. # Motivation Since Ember 2.3, released over a year ago, the framework has enjoyed a feature commonly -referred a **contextual components** that allows components to be dynamically invoked by name +referred to as **contextual components** that allows components to be dynamically invoked by name and also to be wrapped along with arguments and passed as regular values to later on be invoked. -Examples from the blog post of the 2.3 release: +Example from the blog post of the 2.3 release: ```hbs {{#alert-box as |box|}} @@ -27,7 +27,7 @@ Examples from the blog post of the 2.3 release: {{/alert-box}} ``` -This features allows to create very nice domain-specific APIs in components. Some examples +This features allows the creation of very nice domain-specific APIs in components. Some examples of this in the wild can be found in [ember-basic-dropdown](https://github.com/cibernox/ember-basic-dropdown), [ember-form-for](https://github.com/martndemus/ember-form-for) and [ember-power-calendar](https://github.com/cibernox/ember-power-calendar). @@ -36,14 +36,14 @@ exposing helpers with prepopulated arguments or options to provide better APIs. # Detailed design -The design of this feature should be as similar to the **contextual components** feature as -possible so users feel confortable with it immediatly. +The design of this feature should be as similar as possible to the **contextual components** feature, +so users feel confortable with it immediatly. -Therefore the natural option would be the creation of a `helper` helper that depending on the context +Therefore, the natural option would be the creation of a `helper` helper that, depending on the context, invokes a helper by its name or creates a closure helper to pass it around. -However there is an ambiguity with this approach that is not present with components. I'm going to expose -the problem first since it's going to drive the entire design of the feature. +However, there is an ambiguity with this approach that is not present with components. I'm going to expose +the problem first, since it's going to drive the entire design of the feature. ```hbs {{my-component format-date=(helper "moment-format")}} @@ -65,22 +65,14 @@ context of html. By example In those examples above the only option can be immediatly evaluate. -In the proposed syntax of glimmer-components the ambiguity doesn't exists when passing attributes -but it does when passing properties: - -```hbs - - -``` - How is this problem solved? #### Use a different helper for creating closure helpers and to evaluate helpers -To remove the ambiguity, there is two different keywords for the two different features. +To remove the ambiguity, there are two different keywords for the two different features. Ideas include `helper` to create the closure helper and `invoke-helper` to invoke it. -Another possible names borrowed from ruby conventions can be `helper` (closure creator) and `helper!` (invocation). +Another possible names borrowed from Ruby conventions can be `helper` (closure creator) and `helper!` (invocation). Examples: @@ -94,12 +86,11 @@ Examples: {{my-component format-date=(invoke-helper "moment-format")}} ``` -The obvious drawback of this alternative is having two new keywords in ember instead of only one. +The obvious drawback of this alternative is having two new keywords in Ember instead of one. -Ideally since the idea of wrapping a component and a helper is very similar, I think that +Ideally, since the idea of wrapping a component and a helper is very similar, I think that this keyword should be used for both components and helpers and replace the existing overloaded `component` keyword. -Perhaps the transition to glimmer-components will open an oportunity window for this. # How We Teach This @@ -114,9 +105,8 @@ Whatever solution is designed for the component helper must also be take into co # Alternatives -The RFC already discusses the alterniative paths since they are the main subject of the proposal. +The RFC already discusses the alternative paths since they are the main subject of the proposal. # Unresolved questions -Optional, but suggested for first drafts. What parts of the design are still -TBD? +To be determined.