replace earlier binding infrastructure - #408

Merged
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder
Feb 20, 2019
Merged

replace earlier binding infrastructure#408
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder

Conversation

@jonsequitur

@jonsequiturjonsequitur commented Feb 9, 2019

Copy link
Copy Markdown
Contributor

This is attempt #3 at a generalized model binding infrastructure with lessons learned from the previous two iterations. If we think this is a good approach, this is intended to replace the following types and their related code:

  • TypeBinder
  • MethodBinder
  • ReflectionBinder

This is intended to address the following scenarios in a way that is flexible enough to be leveraged within app models, e.g. DragonFruit:

  • Binding input from various sources (ParseResult, service provider, arbitrary inputs such as environment variables, etc.) to arbitrary types (including constructor parameters, property setters, and handler parameters)
  • Binding in the absence of invocation
  • Easier testing of binding operations

It also shifts the code for building options based on a method signature, which DragonFruit uses, into System.CommandLine.DragonFruit. Some of this may later move under the app model work but as it's highly convention-based, we decided that it does not belong in the core library.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 928f0c0 to 22fdb6cCompareFebruary 9, 2019 16:14
@jonsequiturjonsequitur changed the title [WIP] decompose binding[WIP] decomposed model bindingFeb 10, 2019
return GetValues(context, ConstructorDescriptor.ParameterDescriptors);
}

public object CreateInstance(BindingContext context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, consider GetInstance

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how you think about the distinction here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second look, Create is fine

Comment threadsrc/System.CommandLine/Binding/ModelBinder.cs Outdated
new SpecificSymbolValueSource(option));
}

public void BindMemberFromCommand<TValue>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean BindMemberFromArgument? How will a tight coupling between commands and arguments here work with multiple arguments? I do not believe people think about commands having values as much as having arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the above because this isn't the place for it, but to clarify the confusion.

Our implementation is at odds with the ways I believe people think about the problem, and reflects an implementation detail. I do not believe people say "What's the value of that command?" Nor "What's the value of the argument on that option?" I think they would say "What's the value of the argument?" or "What's the value of the option?" and that is how Help seems laid out to me. I think this is going to be a rough cognitive load and reflects an implementation detail, and I know I will keep making this mistake whenever I am thinking about the real problem (the CLI).

But this has nothing to do with the problem we are trying to solve today.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does mean bind from the argument. The concern is a good one. I think conceptually "What is the value for this option" is more intuitive but less precise than "What is the value for this option's argument"? And yes, the value for a command will become more ambiguous with #310.

Comment threadsrc/System.CommandLine/Binding/ModelBinder{T}.cs

namespace System.CommandLine.Binding
{
public class ModelDescriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppModels will need to set just some properties. I think this will be a need for some other cases as well. How would you pass the list of PropertyDescriptors to this class?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean set some properties that were not discovered via reflection?

Comment threadsrc/System.CommandLine/Binding/ModelDescriptor.cs
Comment threadsrc/System.CommandLine/Binding/SpecificSymbolValueSource.cs Outdated
Comment threadsrc/System.CommandLine/Binding/SymbolBindingSide.cs Outdated

public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People may be confused by this - properties now appear to have default values. Not sure if we can work with them.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't intended to being limited the capabilities of reflection. The intention is to be able to annotate the model descriptor so that, for example, if you know that a given type behaviorally has a default, you can define that in the model.


public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning the type default instead of null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 853e3ed to 6eabddaCompareFebruary 17, 2019 17:19
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch 3 times, most recently from 573c2ee to 0693638CompareFebruary 19, 2019 15:09
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 0693638 to 87abf71CompareFebruary 19, 2019 16:46
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 87abf71 to 10c374cCompareFebruary 19, 2019 20:17
@jonsequiturjonsequitur changed the title [WIP] decomposed model bindingreplace earlier binding infrastructureFeb 19, 2019
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequitur merged commit c9450cb into dotnet:masterFeb 20, 2019
@jonsequitur
jonsequitur deleted the decompose-ReflectionBinder branch May 20, 2019 15:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jonsequitur@KathleenDollard
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

replace earlier binding infrastructure - #408

Merged
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder
Feb 20, 2019
Merged

replace earlier binding infrastructure#408
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder

Conversation

@jonsequitur

@jonsequiturjonsequitur commented Feb 9, 2019

Copy link
Copy Markdown
Contributor

This is attempt #3 at a generalized model binding infrastructure with lessons learned from the previous two iterations. If we think this is a good approach, this is intended to replace the following types and their related code:

  • TypeBinder
  • MethodBinder
  • ReflectionBinder

This is intended to address the following scenarios in a way that is flexible enough to be leveraged within app models, e.g. DragonFruit:

  • Binding input from various sources (ParseResult, service provider, arbitrary inputs such as environment variables, etc.) to arbitrary types (including constructor parameters, property setters, and handler parameters)
  • Binding in the absence of invocation
  • Easier testing of binding operations

It also shifts the code for building options based on a method signature, which DragonFruit uses, into System.CommandLine.DragonFruit. Some of this may later move under the app model work but as it's highly convention-based, we decided that it does not belong in the core library.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 928f0c0 to 22fdb6cCompareFebruary 9, 2019 16:14
@jonsequiturjonsequitur changed the title [WIP] decompose binding[WIP] decomposed model bindingFeb 10, 2019
return GetValues(context, ConstructorDescriptor.ParameterDescriptors);
}

public object CreateInstance(BindingContext context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, consider GetInstance

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how you think about the distinction here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second look, Create is fine

Comment threadsrc/System.CommandLine/Binding/ModelBinder.cs Outdated
new SpecificSymbolValueSource(option));
}

public void BindMemberFromCommand<TValue>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean BindMemberFromArgument? How will a tight coupling between commands and arguments here work with multiple arguments? I do not believe people think about commands having values as much as having arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the above because this isn't the place for it, but to clarify the confusion.

Our implementation is at odds with the ways I believe people think about the problem, and reflects an implementation detail. I do not believe people say "What's the value of that command?" Nor "What's the value of the argument on that option?" I think they would say "What's the value of the argument?" or "What's the value of the option?" and that is how Help seems laid out to me. I think this is going to be a rough cognitive load and reflects an implementation detail, and I know I will keep making this mistake whenever I am thinking about the real problem (the CLI).

But this has nothing to do with the problem we are trying to solve today.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does mean bind from the argument. The concern is a good one. I think conceptually "What is the value for this option" is more intuitive but less precise than "What is the value for this option's argument"? And yes, the value for a command will become more ambiguous with #310.

Comment threadsrc/System.CommandLine/Binding/ModelBinder{T}.cs

namespace System.CommandLine.Binding
{
public class ModelDescriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppModels will need to set just some properties. I think this will be a need for some other cases as well. How would you pass the list of PropertyDescriptors to this class?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean set some properties that were not discovered via reflection?

Comment threadsrc/System.CommandLine/Binding/ModelDescriptor.cs
Comment threadsrc/System.CommandLine/Binding/SpecificSymbolValueSource.cs Outdated
Comment threadsrc/System.CommandLine/Binding/SymbolBindingSide.cs Outdated

public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People may be confused by this - properties now appear to have default values. Not sure if we can work with them.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't intended to being limited the capabilities of reflection. The intention is to be able to annotate the model descriptor so that, for example, if you know that a given type behaviorally has a default, you can define that in the model.


public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning the type default instead of null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 853e3ed to 6eabddaCompareFebruary 17, 2019 17:19
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch 3 times, most recently from 573c2ee to 0693638CompareFebruary 19, 2019 15:09
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 0693638 to 87abf71CompareFebruary 19, 2019 16:46
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 87abf71 to 10c374cCompareFebruary 19, 2019 20:17
@jonsequiturjonsequitur changed the title [WIP] decomposed model bindingreplace earlier binding infrastructureFeb 19, 2019
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequitur merged commit c9450cb into dotnet:masterFeb 20, 2019
@jonsequitur
jonsequitur deleted the decompose-ReflectionBinder branch May 20, 2019 15:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jonsequitur@KathleenDollard
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

replace earlier binding infrastructure - #408

Merged
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder
Feb 20, 2019
Merged

replace earlier binding infrastructure#408
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder

Conversation

@jonsequitur

@jonsequiturjonsequitur commented Feb 9, 2019

Copy link
Copy Markdown
Contributor

This is attempt #3 at a generalized model binding infrastructure with lessons learned from the previous two iterations. If we think this is a good approach, this is intended to replace the following types and their related code:

  • TypeBinder
  • MethodBinder
  • ReflectionBinder

This is intended to address the following scenarios in a way that is flexible enough to be leveraged within app models, e.g. DragonFruit:

  • Binding input from various sources (ParseResult, service provider, arbitrary inputs such as environment variables, etc.) to arbitrary types (including constructor parameters, property setters, and handler parameters)
  • Binding in the absence of invocation
  • Easier testing of binding operations

It also shifts the code for building options based on a method signature, which DragonFruit uses, into System.CommandLine.DragonFruit. Some of this may later move under the app model work but as it's highly convention-based, we decided that it does not belong in the core library.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 928f0c0 to 22fdb6cCompareFebruary 9, 2019 16:14
@jonsequiturjonsequitur changed the title [WIP] decompose binding[WIP] decomposed model bindingFeb 10, 2019
return GetValues(context, ConstructorDescriptor.ParameterDescriptors);
}

public object CreateInstance(BindingContext context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, consider GetInstance

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how you think about the distinction here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second look, Create is fine

Comment threadsrc/System.CommandLine/Binding/ModelBinder.cs Outdated
new SpecificSymbolValueSource(option));
}

public void BindMemberFromCommand<TValue>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean BindMemberFromArgument? How will a tight coupling between commands and arguments here work with multiple arguments? I do not believe people think about commands having values as much as having arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the above because this isn't the place for it, but to clarify the confusion.

Our implementation is at odds with the ways I believe people think about the problem, and reflects an implementation detail. I do not believe people say "What's the value of that command?" Nor "What's the value of the argument on that option?" I think they would say "What's the value of the argument?" or "What's the value of the option?" and that is how Help seems laid out to me. I think this is going to be a rough cognitive load and reflects an implementation detail, and I know I will keep making this mistake whenever I am thinking about the real problem (the CLI).

But this has nothing to do with the problem we are trying to solve today.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does mean bind from the argument. The concern is a good one. I think conceptually "What is the value for this option" is more intuitive but less precise than "What is the value for this option's argument"? And yes, the value for a command will become more ambiguous with #310.

Comment threadsrc/System.CommandLine/Binding/ModelBinder{T}.cs

namespace System.CommandLine.Binding
{
public class ModelDescriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppModels will need to set just some properties. I think this will be a need for some other cases as well. How would you pass the list of PropertyDescriptors to this class?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean set some properties that were not discovered via reflection?

Comment threadsrc/System.CommandLine/Binding/ModelDescriptor.cs
Comment threadsrc/System.CommandLine/Binding/SpecificSymbolValueSource.cs Outdated
Comment threadsrc/System.CommandLine/Binding/SymbolBindingSide.cs Outdated

public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People may be confused by this - properties now appear to have default values. Not sure if we can work with them.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't intended to being limited the capabilities of reflection. The intention is to be able to annotate the model descriptor so that, for example, if you know that a given type behaviorally has a default, you can define that in the model.


public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning the type default instead of null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 853e3ed to 6eabddaCompareFebruary 17, 2019 17:19
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch 3 times, most recently from 573c2ee to 0693638CompareFebruary 19, 2019 15:09
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 0693638 to 87abf71CompareFebruary 19, 2019 16:46
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 87abf71 to 10c374cCompareFebruary 19, 2019 20:17
@jonsequiturjonsequitur changed the title [WIP] decomposed model bindingreplace earlier binding infrastructureFeb 19, 2019
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequitur merged commit c9450cb into dotnet:masterFeb 20, 2019
@jonsequitur
jonsequitur deleted the decompose-ReflectionBinder branch May 20, 2019 15:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jonsequitur@KathleenDollard
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

replace earlier binding infrastructure - #408

Merged
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder
Feb 20, 2019
Merged

replace earlier binding infrastructure#408
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder

Conversation

@jonsequitur

@jonsequiturjonsequitur commented Feb 9, 2019

Copy link
Copy Markdown
Contributor

This is attempt #3 at a generalized model binding infrastructure with lessons learned from the previous two iterations. If we think this is a good approach, this is intended to replace the following types and their related code:

  • TypeBinder
  • MethodBinder
  • ReflectionBinder

This is intended to address the following scenarios in a way that is flexible enough to be leveraged within app models, e.g. DragonFruit:

  • Binding input from various sources (ParseResult, service provider, arbitrary inputs such as environment variables, etc.) to arbitrary types (including constructor parameters, property setters, and handler parameters)
  • Binding in the absence of invocation
  • Easier testing of binding operations

It also shifts the code for building options based on a method signature, which DragonFruit uses, into System.CommandLine.DragonFruit. Some of this may later move under the app model work but as it's highly convention-based, we decided that it does not belong in the core library.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 928f0c0 to 22fdb6cCompareFebruary 9, 2019 16:14
@jonsequiturjonsequitur changed the title [WIP] decompose binding[WIP] decomposed model bindingFeb 10, 2019
return GetValues(context, ConstructorDescriptor.ParameterDescriptors);
}

public object CreateInstance(BindingContext context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, consider GetInstance

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how you think about the distinction here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second look, Create is fine

Comment threadsrc/System.CommandLine/Binding/ModelBinder.cs Outdated
new SpecificSymbolValueSource(option));
}

public void BindMemberFromCommand<TValue>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean BindMemberFromArgument? How will a tight coupling between commands and arguments here work with multiple arguments? I do not believe people think about commands having values as much as having arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the above because this isn't the place for it, but to clarify the confusion.

Our implementation is at odds with the ways I believe people think about the problem, and reflects an implementation detail. I do not believe people say "What's the value of that command?" Nor "What's the value of the argument on that option?" I think they would say "What's the value of the argument?" or "What's the value of the option?" and that is how Help seems laid out to me. I think this is going to be a rough cognitive load and reflects an implementation detail, and I know I will keep making this mistake whenever I am thinking about the real problem (the CLI).

But this has nothing to do with the problem we are trying to solve today.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does mean bind from the argument. The concern is a good one. I think conceptually "What is the value for this option" is more intuitive but less precise than "What is the value for this option's argument"? And yes, the value for a command will become more ambiguous with #310.

Comment threadsrc/System.CommandLine/Binding/ModelBinder{T}.cs

namespace System.CommandLine.Binding
{
public class ModelDescriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppModels will need to set just some properties. I think this will be a need for some other cases as well. How would you pass the list of PropertyDescriptors to this class?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean set some properties that were not discovered via reflection?

Comment threadsrc/System.CommandLine/Binding/ModelDescriptor.cs
Comment threadsrc/System.CommandLine/Binding/SpecificSymbolValueSource.cs Outdated
Comment threadsrc/System.CommandLine/Binding/SymbolBindingSide.cs Outdated

public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People may be confused by this - properties now appear to have default values. Not sure if we can work with them.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't intended to being limited the capabilities of reflection. The intention is to be able to annotate the model descriptor so that, for example, if you know that a given type behaviorally has a default, you can define that in the model.


public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning the type default instead of null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 853e3ed to 6eabddaCompareFebruary 17, 2019 17:19
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch 3 times, most recently from 573c2ee to 0693638CompareFebruary 19, 2019 15:09
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 0693638 to 87abf71CompareFebruary 19, 2019 16:46
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 87abf71 to 10c374cCompareFebruary 19, 2019 20:17
@jonsequiturjonsequitur changed the title [WIP] decomposed model bindingreplace earlier binding infrastructureFeb 19, 2019
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequitur merged commit c9450cb into dotnet:masterFeb 20, 2019
@jonsequitur
jonsequitur deleted the decompose-ReflectionBinder branch May 20, 2019 15:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jonsequitur@KathleenDollard
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

replace earlier binding infrastructure - #408

Merged
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder
Feb 20, 2019
Merged

replace earlier binding infrastructure#408
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder

Conversation

@jonsequitur

@jonsequiturjonsequitur commented Feb 9, 2019

Copy link
Copy Markdown
Contributor

This is attempt #3 at a generalized model binding infrastructure with lessons learned from the previous two iterations. If we think this is a good approach, this is intended to replace the following types and their related code:

  • TypeBinder
  • MethodBinder
  • ReflectionBinder

This is intended to address the following scenarios in a way that is flexible enough to be leveraged within app models, e.g. DragonFruit:

  • Binding input from various sources (ParseResult, service provider, arbitrary inputs such as environment variables, etc.) to arbitrary types (including constructor parameters, property setters, and handler parameters)
  • Binding in the absence of invocation
  • Easier testing of binding operations

It also shifts the code for building options based on a method signature, which DragonFruit uses, into System.CommandLine.DragonFruit. Some of this may later move under the app model work but as it's highly convention-based, we decided that it does not belong in the core library.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 928f0c0 to 22fdb6cCompareFebruary 9, 2019 16:14
@jonsequiturjonsequitur changed the title [WIP] decompose binding[WIP] decomposed model bindingFeb 10, 2019
return GetValues(context, ConstructorDescriptor.ParameterDescriptors);
}

public object CreateInstance(BindingContext context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, consider GetInstance

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how you think about the distinction here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second look, Create is fine

Comment threadsrc/System.CommandLine/Binding/ModelBinder.cs Outdated
new SpecificSymbolValueSource(option));
}

public void BindMemberFromCommand<TValue>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean BindMemberFromArgument? How will a tight coupling between commands and arguments here work with multiple arguments? I do not believe people think about commands having values as much as having arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the above because this isn't the place for it, but to clarify the confusion.

Our implementation is at odds with the ways I believe people think about the problem, and reflects an implementation detail. I do not believe people say "What's the value of that command?" Nor "What's the value of the argument on that option?" I think they would say "What's the value of the argument?" or "What's the value of the option?" and that is how Help seems laid out to me. I think this is going to be a rough cognitive load and reflects an implementation detail, and I know I will keep making this mistake whenever I am thinking about the real problem (the CLI).

But this has nothing to do with the problem we are trying to solve today.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does mean bind from the argument. The concern is a good one. I think conceptually "What is the value for this option" is more intuitive but less precise than "What is the value for this option's argument"? And yes, the value for a command will become more ambiguous with #310.

Comment threadsrc/System.CommandLine/Binding/ModelBinder{T}.cs

namespace System.CommandLine.Binding
{
public class ModelDescriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppModels will need to set just some properties. I think this will be a need for some other cases as well. How would you pass the list of PropertyDescriptors to this class?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean set some properties that were not discovered via reflection?

Comment threadsrc/System.CommandLine/Binding/ModelDescriptor.cs
Comment threadsrc/System.CommandLine/Binding/SpecificSymbolValueSource.cs Outdated
Comment threadsrc/System.CommandLine/Binding/SymbolBindingSide.cs Outdated

public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People may be confused by this - properties now appear to have default values. Not sure if we can work with them.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't intended to being limited the capabilities of reflection. The intention is to be able to annotate the model descriptor so that, for example, if you know that a given type behaviorally has a default, you can define that in the model.


public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning the type default instead of null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 853e3ed to 6eabddaCompareFebruary 17, 2019 17:19
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch 3 times, most recently from 573c2ee to 0693638CompareFebruary 19, 2019 15:09
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 0693638 to 87abf71CompareFebruary 19, 2019 16:46
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 87abf71 to 10c374cCompareFebruary 19, 2019 20:17
@jonsequiturjonsequitur changed the title [WIP] decomposed model bindingreplace earlier binding infrastructureFeb 19, 2019
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequitur merged commit c9450cb into dotnet:masterFeb 20, 2019
@jonsequitur
jonsequitur deleted the decompose-ReflectionBinder branch May 20, 2019 15:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jonsequitur@KathleenDollard
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

replace earlier binding infrastructure - #408

Merged
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder
Feb 20, 2019
Merged

replace earlier binding infrastructure#408
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder

Conversation

@jonsequitur

@jonsequiturjonsequitur commented Feb 9, 2019

Copy link
Copy Markdown
Contributor

This is attempt #3 at a generalized model binding infrastructure with lessons learned from the previous two iterations. If we think this is a good approach, this is intended to replace the following types and their related code:

  • TypeBinder
  • MethodBinder
  • ReflectionBinder

This is intended to address the following scenarios in a way that is flexible enough to be leveraged within app models, e.g. DragonFruit:

  • Binding input from various sources (ParseResult, service provider, arbitrary inputs such as environment variables, etc.) to arbitrary types (including constructor parameters, property setters, and handler parameters)
  • Binding in the absence of invocation
  • Easier testing of binding operations

It also shifts the code for building options based on a method signature, which DragonFruit uses, into System.CommandLine.DragonFruit. Some of this may later move under the app model work but as it's highly convention-based, we decided that it does not belong in the core library.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 928f0c0 to 22fdb6cCompareFebruary 9, 2019 16:14
@jonsequiturjonsequitur changed the title [WIP] decompose binding[WIP] decomposed model bindingFeb 10, 2019
return GetValues(context, ConstructorDescriptor.ParameterDescriptors);
}

public object CreateInstance(BindingContext context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, consider GetInstance

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how you think about the distinction here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second look, Create is fine

Comment threadsrc/System.CommandLine/Binding/ModelBinder.cs Outdated
new SpecificSymbolValueSource(option));
}

public void BindMemberFromCommand<TValue>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean BindMemberFromArgument? How will a tight coupling between commands and arguments here work with multiple arguments? I do not believe people think about commands having values as much as having arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the above because this isn't the place for it, but to clarify the confusion.

Our implementation is at odds with the ways I believe people think about the problem, and reflects an implementation detail. I do not believe people say "What's the value of that command?" Nor "What's the value of the argument on that option?" I think they would say "What's the value of the argument?" or "What's the value of the option?" and that is how Help seems laid out to me. I think this is going to be a rough cognitive load and reflects an implementation detail, and I know I will keep making this mistake whenever I am thinking about the real problem (the CLI).

But this has nothing to do with the problem we are trying to solve today.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does mean bind from the argument. The concern is a good one. I think conceptually "What is the value for this option" is more intuitive but less precise than "What is the value for this option's argument"? And yes, the value for a command will become more ambiguous with #310.

Comment threadsrc/System.CommandLine/Binding/ModelBinder{T}.cs

namespace System.CommandLine.Binding
{
public class ModelDescriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppModels will need to set just some properties. I think this will be a need for some other cases as well. How would you pass the list of PropertyDescriptors to this class?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean set some properties that were not discovered via reflection?

Comment threadsrc/System.CommandLine/Binding/ModelDescriptor.cs
Comment threadsrc/System.CommandLine/Binding/SpecificSymbolValueSource.cs Outdated
Comment threadsrc/System.CommandLine/Binding/SymbolBindingSide.cs Outdated

public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People may be confused by this - properties now appear to have default values. Not sure if we can work with them.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't intended to being limited the capabilities of reflection. The intention is to be able to annotate the model descriptor so that, for example, if you know that a given type behaviorally has a default, you can define that in the model.


public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning the type default instead of null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 853e3ed to 6eabddaCompareFebruary 17, 2019 17:19
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch 3 times, most recently from 573c2ee to 0693638CompareFebruary 19, 2019 15:09
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 0693638 to 87abf71CompareFebruary 19, 2019 16:46
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 87abf71 to 10c374cCompareFebruary 19, 2019 20:17
@jonsequiturjonsequitur changed the title [WIP] decomposed model bindingreplace earlier binding infrastructureFeb 19, 2019
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequitur merged commit c9450cb into dotnet:masterFeb 20, 2019
@jonsequitur
jonsequitur deleted the decompose-ReflectionBinder branch May 20, 2019 15:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jonsequitur@KathleenDollard
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

replace earlier binding infrastructure - #408

Merged
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder
Feb 20, 2019
Merged

replace earlier binding infrastructure#408
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder

Conversation

@jonsequitur

@jonsequiturjonsequitur commented Feb 9, 2019

Copy link
Copy Markdown
Contributor

This is attempt #3 at a generalized model binding infrastructure with lessons learned from the previous two iterations. If we think this is a good approach, this is intended to replace the following types and their related code:

  • TypeBinder
  • MethodBinder
  • ReflectionBinder

This is intended to address the following scenarios in a way that is flexible enough to be leveraged within app models, e.g. DragonFruit:

  • Binding input from various sources (ParseResult, service provider, arbitrary inputs such as environment variables, etc.) to arbitrary types (including constructor parameters, property setters, and handler parameters)
  • Binding in the absence of invocation
  • Easier testing of binding operations

It also shifts the code for building options based on a method signature, which DragonFruit uses, into System.CommandLine.DragonFruit. Some of this may later move under the app model work but as it's highly convention-based, we decided that it does not belong in the core library.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 928f0c0 to 22fdb6cCompareFebruary 9, 2019 16:14
@jonsequiturjonsequitur changed the title [WIP] decompose binding[WIP] decomposed model bindingFeb 10, 2019
return GetValues(context, ConstructorDescriptor.ParameterDescriptors);
}

public object CreateInstance(BindingContext context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, consider GetInstance

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how you think about the distinction here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second look, Create is fine

Comment threadsrc/System.CommandLine/Binding/ModelBinder.cs Outdated
new SpecificSymbolValueSource(option));
}

public void BindMemberFromCommand<TValue>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean BindMemberFromArgument? How will a tight coupling between commands and arguments here work with multiple arguments? I do not believe people think about commands having values as much as having arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the above because this isn't the place for it, but to clarify the confusion.

Our implementation is at odds with the ways I believe people think about the problem, and reflects an implementation detail. I do not believe people say "What's the value of that command?" Nor "What's the value of the argument on that option?" I think they would say "What's the value of the argument?" or "What's the value of the option?" and that is how Help seems laid out to me. I think this is going to be a rough cognitive load and reflects an implementation detail, and I know I will keep making this mistake whenever I am thinking about the real problem (the CLI).

But this has nothing to do with the problem we are trying to solve today.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does mean bind from the argument. The concern is a good one. I think conceptually "What is the value for this option" is more intuitive but less precise than "What is the value for this option's argument"? And yes, the value for a command will become more ambiguous with #310.

Comment threadsrc/System.CommandLine/Binding/ModelBinder{T}.cs

namespace System.CommandLine.Binding
{
public class ModelDescriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppModels will need to set just some properties. I think this will be a need for some other cases as well. How would you pass the list of PropertyDescriptors to this class?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean set some properties that were not discovered via reflection?

Comment threadsrc/System.CommandLine/Binding/ModelDescriptor.cs
Comment threadsrc/System.CommandLine/Binding/SpecificSymbolValueSource.cs Outdated
Comment threadsrc/System.CommandLine/Binding/SymbolBindingSide.cs Outdated

public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People may be confused by this - properties now appear to have default values. Not sure if we can work with them.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't intended to being limited the capabilities of reflection. The intention is to be able to annotate the model descriptor so that, for example, if you know that a given type behaviorally has a default, you can define that in the model.


public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning the type default instead of null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 853e3ed to 6eabddaCompareFebruary 17, 2019 17:19
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch 3 times, most recently from 573c2ee to 0693638CompareFebruary 19, 2019 15:09
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 0693638 to 87abf71CompareFebruary 19, 2019 16:46
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 87abf71 to 10c374cCompareFebruary 19, 2019 20:17
@jonsequiturjonsequitur changed the title [WIP] decomposed model bindingreplace earlier binding infrastructureFeb 19, 2019
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequitur merged commit c9450cb into dotnet:masterFeb 20, 2019
@jonsequitur
jonsequitur deleted the decompose-ReflectionBinder branch May 20, 2019 15:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jonsequitur@KathleenDollard
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

replace earlier binding infrastructure - #408

Merged
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder
Feb 20, 2019
Merged

replace earlier binding infrastructure#408
jonsequitur merged 14 commits into
dotnet:masterfrom
jonsequitur:decompose-ReflectionBinder

Conversation

@jonsequitur

@jonsequiturjonsequitur commented Feb 9, 2019

Copy link
Copy Markdown
Contributor

This is attempt #3 at a generalized model binding infrastructure with lessons learned from the previous two iterations. If we think this is a good approach, this is intended to replace the following types and their related code:

  • TypeBinder
  • MethodBinder
  • ReflectionBinder

This is intended to address the following scenarios in a way that is flexible enough to be leveraged within app models, e.g. DragonFruit:

  • Binding input from various sources (ParseResult, service provider, arbitrary inputs such as environment variables, etc.) to arbitrary types (including constructor parameters, property setters, and handler parameters)
  • Binding in the absence of invocation
  • Easier testing of binding operations

It also shifts the code for building options based on a method signature, which DragonFruit uses, into System.CommandLine.DragonFruit. Some of this may later move under the app model work but as it's highly convention-based, we decided that it does not belong in the core library.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 928f0c0 to 22fdb6cCompareFebruary 9, 2019 16:14
@jonsequiturjonsequitur changed the title [WIP] decompose binding[WIP] decomposed model bindingFeb 10, 2019
return GetValues(context, ConstructorDescriptor.ParameterDescriptors);
}

public object CreateInstance(BindingContext context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, consider GetInstance

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how you think about the distinction here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second look, Create is fine

Comment threadsrc/System.CommandLine/Binding/ModelBinder.cs Outdated
new SpecificSymbolValueSource(option));
}

public void BindMemberFromCommand<TValue>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean BindMemberFromArgument? How will a tight coupling between commands and arguments here work with multiple arguments? I do not believe people think about commands having values as much as having arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the above because this isn't the place for it, but to clarify the confusion.

Our implementation is at odds with the ways I believe people think about the problem, and reflects an implementation detail. I do not believe people say "What's the value of that command?" Nor "What's the value of the argument on that option?" I think they would say "What's the value of the argument?" or "What's the value of the option?" and that is how Help seems laid out to me. I think this is going to be a rough cognitive load and reflects an implementation detail, and I know I will keep making this mistake whenever I am thinking about the real problem (the CLI).

But this has nothing to do with the problem we are trying to solve today.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does mean bind from the argument. The concern is a good one. I think conceptually "What is the value for this option" is more intuitive but less precise than "What is the value for this option's argument"? And yes, the value for a command will become more ambiguous with #310.

Comment threadsrc/System.CommandLine/Binding/ModelBinder{T}.cs

namespace System.CommandLine.Binding
{
public class ModelDescriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppModels will need to set just some properties. I think this will be a need for some other cases as well. How would you pass the list of PropertyDescriptors to this class?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean set some properties that were not discovered via reflection?

Comment threadsrc/System.CommandLine/Binding/ModelDescriptor.cs
Comment threadsrc/System.CommandLine/Binding/SpecificSymbolValueSource.cs Outdated
Comment threadsrc/System.CommandLine/Binding/SymbolBindingSide.cs Outdated

public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People may be confused by this - properties now appear to have default values. Not sure if we can work with them.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't intended to being limited the capabilities of reflection. The intention is to be able to annotate the model descriptor so that, for example, if you know that a given type behaviorally has a default, you can define that in the model.


public bool HasDefaultValue => false;

public object GetDefaultValue() => null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning the type default instead of null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 853e3ed to 6eabddaCompareFebruary 17, 2019 17:19
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch 3 times, most recently from 573c2ee to 0693638CompareFebruary 19, 2019 15:09
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 0693638 to 87abf71CompareFebruary 19, 2019 16:46
@jonsequitur
jonsequiturforce-pushed the decompose-ReflectionBinder branch from 87abf71 to 10c374cCompareFebruary 19, 2019 20:17
@jonsequiturjonsequitur changed the title [WIP] decomposed model bindingreplace earlier binding infrastructureFeb 19, 2019
@jonsequitur

Copy link
Copy Markdown
ContributorAuthor

@dotnet-bot test Ubuntu16.04 Release

@jonsequitur
jonsequitur merged commit c9450cb into dotnet:masterFeb 20, 2019
@jonsequitur
jonsequitur deleted the decompose-ReflectionBinder branch May 20, 2019 15:45
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jonsequitur@KathleenDollard