{"action":"created","comment":{"url":"https://api.github.com/repos/puppetlabs/puppet/pulls/comments/61713297","id":61713297,"diff_hunk":"@@ -0,0 +1,155 @@\n+module Puppet::Pops\n+module Types\n+\n+# An unparameterized type that represents all VersionRange instances\n+#\n+# @api public\n+class PSemVerRangeType < PScalarType\n+  # Check if a version is included in a version range. The version can be a string or\n+  # a `Semantic::SemVer`\n+  #\n+  # @param range [Semantic::VersionRange] the range to match against\n+  # @param version [Semantic::Version,String] the version to match\n+  # @return [Boolean] `true` if the range includes the given version\n+  #\n+  # @api public\n+  def self.include?(range, version)\n+    case version\n+    when Semantic::Version\n+      range.include?(version)\n+    when String\n+      begin\n+        range.include?(Semantic::Version.parse(version))\n+      rescue Semantic::Version::ValidationFailure\n+        false\n+      end\n+    else\n+      false\n+    end\n+  end\n+\n+  # Checks if range _a_ is a sub-range of (i.e. completely covered by) range _b_\n+  # @param a [Semantic::VersionRange] the first range\n+  # @param b [Semantic::VersionRange] the second range\n+  #\n+  # @return [Boolean] `true` if _a_ is completely covered by _b_\n+  def self.covered_by?(a, b)\n+    b.begin <= a.begin && (b.end > a.end || b.end == a.end && (!b.exclude_end? || a.exclude_end?))\n+  end\n+\n+  # Merge two ranges so that the result matches all versions matched by both. A merge\n+  # is only possible when the ranges are either adjacent or have an overlap.\n+  #\n+  # @param a [Semantic::VersionRange] the first range\n+  # @param b [Semantic::VersionRange] the second range\n+  # @return [Semantic::VersionRange,nil] the result of the merge\n+  #\n+  # @api public\n+  def self.merge(a, b)\n+    if a.include?(b.begin) || b.include?(a.begin)\n+      max = [a.end, b.end].max\n+      exclude_end = false\n+      if a.exclude_end?\n+        exclude_end = max == a.end && (max > b.end || b.exclude_end?)\n+      elsif b.exclude_end?\n+        exclude_end = max == b.end && (max > a.end || a.exclude_end?)\n+      end\n+      Semantic::VersionRange.new([a.begin, b.begin].min, max, exclude_end)\n+    elsif a.exclude_end? && a.end == b.begin\n+      # Adjacent, a before b\n+      Semantic::VersionRange.new(a.begin, b.end, b.exclude_end?)\n+    elsif b.exclude_end? && b.end == a.begin\n+      # Adjacent, b before a\n+      Semantic::VersionRange.new(b.begin, a.end, a.exclude_end?)\n+    else\n+      # No overlap\n+      nil\n+    end\n+  end\n+\n+  def instance?(o, guard = nil)\n+    o.is_a?(Semantic::VersionRange)\n+  end\n+\n+  def eql?(o)\n+    self.class == o.class\n+  end\n+\n+  def hash?\n+    super ^ @version_range.hash\n+  end\n+\n+  def self.new_function(_, loader)\n+    range_expr = \"\\\\A#{range_pattern}\\\\Z\"\n+    @@new_function ||= Puppet::Functions.create_loaded_function(:new_VersionRange, loader) do\n+      # Constructs a regexp pattern that matches a VersionRange as specified by\n+      #\n+      # https://github.com/npm/node-semver#range-grammar\n+      #\n+      # The logical or || operator is not implemented since it effectively builds\n+      # an array of ranges that may be disparate. The {{Semantic::VersionRange}} inherits\n+      # from the standard ruby range. It must be possible to describe that range in terms\n+      # of min, max, and exclude max.\n+      #\n+      # The Puppet Version type is parameterized and accepts multiple ranges so creating such\n+      # constraints is still possible. It will just require several parameters rather than one\n+      # parameter containing the '||' operator.\n+      #","path":"lib/puppet/pops/types/p_sem_ver_range_type.rb","position":97,"original_position":97,"commit_id":"0066a2087f3ed2fd1043e7b37efb758ee397b94d","original_commit_id":"6e8ca3bc8386fac55beef284ca80870e28f25689","user":{"login":"thallgren","id":209495,"avatar_url":"https://avatars.githubusercontent.com/u/209495?v=3","gravatar_id":"","url":"https://api.github.com/users/thallgren","html_url":"https://github.com/thallgren","followers_url":"https://api.github.com/users/thallgren/followers","following_url":"https://api.github.com/users/thallgren/following{/other_user}","gists_url":"https://api.github.com/users/thallgren/gists{/gist_id}","starred_url":"https://api.github.com/users/thallgren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thallgren/subscriptions","organizations_url":"https://api.github.com/users/thallgren/orgs","repos_url":"https://api.github.com/users/thallgren/repos","events_url":"https://api.github.com/users/thallgren/events{/privacy}","received_events_url":"https://api.github.com/users/thallgren/received_events","type":"User","site_admin":false},"body":"Before we move this into the `new` function I think the documentation already present there must be reorganized and have a structure that will allow easy overview of what types that can be created and how. At present it's a just a long list of \"conversions\" with no index, and just patching more text onto that doesn't strike me as a solution that will be helpful to the user. Reorging and preparing that doc to be extended is beyond the scope of this PR. I therefor suggest that we leave the doc for the SemVer and SemVerRange where it is right now and instead create a separate ticket on how to improve the documentation of the `new` function to make it more extendable.\r\n\r\nSide note:\r\nI think the term \"conversion\" is fine when there's one argument, or perhaps one argument with an additional argument that says how the first argument should be interpreted (like Integer('0xFF', 16)) but it doesn't fit the bill for expressions like these:\r\n```\r\n$v1 = Version.new(1, 2, 3)\r\n$v2 = Version.new(3, 2, 0, 'beta')\r\n$range = VersionRange.new($v1, $v2, false)\r\n```\r\n","created_at":"2016-05-02T08:07:12Z","updated_at":"2016-05-02T08:07:12Z","html_url":"https://github.com/puppetlabs/puppet/pull/4927#discussion_r61713297","pull_request_url":"https://api.github.com/repos/puppetlabs/puppet/pulls/4927","_links":{"self":{"href":"https://api.github.com/repos/puppetlabs/puppet/pulls/comments/61713297"},"html":{"href":"https://github.com/puppetlabs/puppet/pull/4927#discussion_r61713297"},"pull_request":{"href":"https://api.github.com/repos/puppetlabs/puppet/pulls/4927"}}},"pull_request":{"url":"https://api.github.com/repos/puppetlabs/puppet/pulls/4927","id":68374931,"html_url":"https://github.com/puppetlabs/puppet/pull/4927","diff_url":"https://github.com/puppetlabs/puppet/pull/4927.diff","patch_url":"https://github.com/puppetlabs/puppet/pull/4927.patch","issue_url":"https://api.github.com/repos/puppetlabs/puppet/issues/4927","number":4927,"state":"open","locked":false,"title":"(PUP-6221) Add Semantic versioning to the Puppet Type System","user":{"login":"thallgren","id":209495,"avatar_url":"https://avatars.githubusercontent.com/u/209495?v=3","gravatar_id":"","url":"https://api.github.com/users/thallgren","html_url":"https://github.com/thallgren","followers_url":"https://api.github.com/users/thallgren/followers","following_url":"https://api.github.com/users/thallgren/following{/other_user}","gists_url":"https://api.github.com/users/thallgren/gists{/gist_id}","starred_url":"https://api.github.com/users/thallgren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thallgren/subscriptions","organizations_url":"https://api.github.com/users/thallgren/orgs","repos_url":"https://api.github.com/users/thallgren/repos","events_url":"https://api.github.com/users/thallgren/events{/privacy}","received_events_url":"https://api.github.com/users/thallgren/received_events","type":"User","site_admin":false},"body":"This PR adds the two types `SemVer` and `SemVerRange` to the Puppet\r\nType System. The `SemVer` is a parameterized type and it's arguments can\r\nbe either strings or `SemVerRange` instances.\r\n\r\nA `SemVer` type is constrained by it's contained `SemVerRanges`. If it has\r\nno ranges, then the type represents all `SemVers`. If it has ranges, then\r\nthe type represents all types that matches any of the ranges.\r\n\r\nThe ranges of a `SemVer` type will be normalized so that any range that\r\nintersects with another range automatically forms a new range. This is\r\nneeded to get the type arithmetic working correctly in cases like:\r\n```\r\n$x = SemVer['>=1.0.0 <2.0.0', '>=1.5.0 <3.0.0']\r\n$y = SemVer['>=1.2.0 <2.8.0']\r\n$x > $y == true\r\n```","created_at":"2016-04-29T13:54:30Z","updated_at":"2016-05-02T08:07:12Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3bffde278e9bf8dfda3ae38ed8524625637017c6","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/puppetlabs/puppet/pulls/4927/commits","review_comments_url":"https://api.github.com/repos/puppetlabs/puppet/pulls/4927/comments","review_comment_url":"https://api.github.com/repos/puppetlabs/puppet/pulls/comments{/number}","comments_url":"https://api.github.com/repos/puppetlabs/puppet/issues/4927/comments","statuses_url":"https://api.github.com/repos/puppetlabs/puppet/statuses/0066a2087f3ed2fd1043e7b37efb758ee397b94d","head":{"label":"thallgren:issue/pup-6221/semver-types","ref":"issue/pup-6221/semver-types","sha":"0066a2087f3ed2fd1043e7b37efb758ee397b94d","user":{"login":"thallgren","id":209495,"avatar_url":"https://avatars.githubusercontent.com/u/209495?v=3","gravatar_id":"","url":"https://api.github.com/users/thallgren","html_url":"https://github.com/thallgren","followers_url":"https://api.github.com/users/thallgren/followers","following_url":"https://api.github.com/users/thallgren/following{/other_user}","gists_url":"https://api.github.com/users/thallgren/gists{/gist_id}","starred_url":"https://api.github.com/users/thallgren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thallgren/subscriptions","organizations_url":"https://api.github.com/users/thallgren/orgs","repos_url":"https://api.github.com/users/thallgren/repos","events_url":"https://api.github.com/users/thallgren/events{/privacy}","received_events_url":"https://api.github.com/users/thallgren/received_events","type":"User","site_admin":false},"repo":{"id":15137589,"name":"puppet","full_name":"thallgren/puppet","owner":{"login":"thallgren","id":209495,"avatar_url":"https://avatars.githubusercontent.com/u/209495?v=3","gravatar_id":"","url":"https://api.github.com/users/thallgren","html_url":"https://github.com/thallgren","followers_url":"https://api.github.com/users/thallgren/followers","following_url":"https://api.github.com/users/thallgren/following{/other_user}","gists_url":"https://api.github.com/users/thallgren/gists{/gist_id}","starred_url":"https://api.github.com/users/thallgren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thallgren/subscriptions","organizations_url":"https://api.github.com/users/thallgren/orgs","repos_url":"https://api.github.com/users/thallgren/repos","events_url":"https://api.github.com/users/thallgren/events{/privacy}","received_events_url":"https://api.github.com/users/thallgren/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/thallgren/puppet","description":"Server automation framework and application","fork":true,"url":"https://api.github.com/repos/thallgren/puppet","forks_url":"https://api.github.com/repos/thallgren/puppet/forks","keys_url":"https://api.github.com/repos/thallgren/puppet/keys{/key_id}","collaborators_url":"https://api.github.com/repos/thallgren/puppet/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/thallgren/puppet/teams","hooks_url":"https://api.github.com/repos/thallgren/puppet/hooks","issue_events_url":"https://api.github.com/repos/thallgren/puppet/issues/events{/number}","events_url":"https://api.github.com/repos/thallgren/puppet/events","assignees_url":"https://api.github.com/repos/thallgren/puppet/assignees{/user}","branches_url":"https://api.github.com/repos/thallgren/puppet/branches{/branch}","tags_url":"https://api.github.com/repos/thallgren/puppet/tags","blobs_url":"https://api.github.com/repos/thallgren/puppet/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/thallgren/puppet/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/thallgren/puppet/git/refs{/sha}","trees_url":"https://api.github.com/repos/thallgren/puppet/git/trees{/sha}","statuses_url":"https://api.github.com/repos/thallgren/puppet/statuses/{sha}","languages_url":"https://api.github.com/repos/thallgren/puppet/languages","stargazers_url":"https://api.github.com/repos/thallgren/puppet/stargazers","contributors_url":"https://api.github.com/repos/thallgren/puppet/contributors","subscribers_url":"https://api.github.com/repos/thallgren/puppet/subscribers","subscription_url":"https://api.github.com/repos/thallgren/puppet/subscription","commits_url":"https://api.github.com/repos/thallgren/puppet/commits{/sha}","git_commits_url":"https://api.github.com/repos/thallgren/puppet/git/commits{/sha}","comments_url":"https://api.github.com/repos/thallgren/puppet/comments{/number}","issue_comment_url":"https://api.github.com/repos/thallgren/puppet/issues/comments{/number}","contents_url":"https://api.github.com/repos/thallgren/puppet/contents/{+path}","compare_url":"https://api.github.com/repos/thallgren/puppet/compare/{base}...{head}","merges_url":"https://api.github.com/repos/thallgren/puppet/merges","archive_url":"https://api.github.com/repos/thallgren/puppet/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/thallgren/puppet/downloads","issues_url":"https://api.github.com/repos/thallgren/puppet/issues{/number}","pulls_url":"https://api.github.com/repos/thallgren/puppet/pulls{/number}","milestones_url":"https://api.github.com/repos/thallgren/puppet/milestones{/number}","notifications_url":"https://api.github.com/repos/thallgren/puppet/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/thallgren/puppet/labels{/name}","releases_url":"https://api.github.com/repos/thallgren/puppet/releases{/id}","deployments_url":"https://api.github.com/repos/thallgren/puppet/deployments","created_at":"2013-12-12T14:09:32Z","updated_at":"2015-01-21T18:51:48Z","pushed_at":"2016-04-30T09:39:37Z","git_url":"git://github.com/thallgren/puppet.git","ssh_url":"git@github.com:thallgren/puppet.git","clone_url":"https://github.com/thallgren/puppet.git","svn_url":"https://github.com/thallgren/puppet","homepage":"http://www.puppetlabs.com/puppet/introduction/","size":51560,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"puppetlabs:master","ref":"master","sha":"a3c6ffa4ff91a94fde39727f73a512f5c051ef09","user":{"login":"puppetlabs","id":234268,"avatar_url":"https://avatars.githubusercontent.com/u/234268?v=3","gravatar_id":"","url":"https://api.github.com/users/puppetlabs","html_url":"https://github.com/puppetlabs","followers_url":"https://api.github.com/users/puppetlabs/followers","following_url":"https://api.github.com/users/puppetlabs/following{/other_user}","gists_url":"https://api.github.com/users/puppetlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/puppetlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puppetlabs/subscriptions","organizations_url":"https://api.github.com/users/puppetlabs/orgs","repos_url":"https://api.github.com/users/puppetlabs/repos","events_url":"https://api.github.com/users/puppetlabs/events{/privacy}","received_events_url":"https://api.github.com/users/puppetlabs/received_events","type":"Organization","site_admin":false},"repo":{"id":910744,"name":"puppet","full_name":"puppetlabs/puppet","owner":{"login":"puppetlabs","id":234268,"avatar_url":"https://avatars.githubusercontent.com/u/234268?v=3","gravatar_id":"","url":"https://api.github.com/users/puppetlabs","html_url":"https://github.com/puppetlabs","followers_url":"https://api.github.com/users/puppetlabs/followers","following_url":"https://api.github.com/users/puppetlabs/following{/other_user}","gists_url":"https://api.github.com/users/puppetlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/puppetlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puppetlabs/subscriptions","organizations_url":"https://api.github.com/users/puppetlabs/orgs","repos_url":"https://api.github.com/users/puppetlabs/repos","events_url":"https://api.github.com/users/puppetlabs/events{/privacy}","received_events_url":"https://api.github.com/users/puppetlabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/puppetlabs/puppet","description":"Server automation framework and application","fork":false,"url":"https://api.github.com/repos/puppetlabs/puppet","forks_url":"https://api.github.com/repos/puppetlabs/puppet/forks","keys_url":"https://api.github.com/repos/puppetlabs/puppet/keys{/key_id}","collaborators_url":"https://api.github.com/repos/puppetlabs/puppet/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/puppetlabs/puppet/teams","hooks_url":"https://api.github.com/repos/puppetlabs/puppet/hooks","issue_events_url":"https://api.github.com/repos/puppetlabs/puppet/issues/events{/number}","events_url":"https://api.github.com/repos/puppetlabs/puppet/events","assignees_url":"https://api.github.com/repos/puppetlabs/puppet/assignees{/user}","branches_url":"https://api.github.com/repos/puppetlabs/puppet/branches{/branch}","tags_url":"https://api.github.com/repos/puppetlabs/puppet/tags","blobs_url":"https://api.github.com/repos/puppetlabs/puppet/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/puppetlabs/puppet/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/puppetlabs/puppet/git/refs{/sha}","trees_url":"https://api.github.com/repos/puppetlabs/puppet/git/trees{/sha}","statuses_url":"https://api.github.com/repos/puppetlabs/puppet/statuses/{sha}","languages_url":"https://api.github.com/repos/puppetlabs/puppet/languages","stargazers_url":"https://api.github.com/repos/puppetlabs/puppet/stargazers","contributors_url":"https://api.github.com/repos/puppetlabs/puppet/contributors","subscribers_url":"https://api.github.com/repos/puppetlabs/puppet/subscribers","subscription_url":"https://api.github.com/repos/puppetlabs/puppet/subscription","commits_url":"https://api.github.com/repos/puppetlabs/puppet/commits{/sha}","git_commits_url":"https://api.github.com/repos/puppetlabs/puppet/git/commits{/sha}","comments_url":"https://api.github.com/repos/puppetlabs/puppet/comments{/number}","issue_comment_url":"https://api.github.com/repos/puppetlabs/puppet/issues/comments{/number}","contents_url":"https://api.github.com/repos/puppetlabs/puppet/contents/{+path}","compare_url":"https://api.github.com/repos/puppetlabs/puppet/compare/{base}...{head}","merges_url":"https://api.github.com/repos/puppetlabs/puppet/merges","archive_url":"https://api.github.com/repos/puppetlabs/puppet/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/puppetlabs/puppet/downloads","issues_url":"https://api.github.com/repos/puppetlabs/puppet/issues{/number}","pulls_url":"https://api.github.com/repos/puppetlabs/puppet/pulls{/number}","milestones_url":"https://api.github.com/repos/puppetlabs/puppet/milestones{/number}","notifications_url":"https://api.github.com/repos/puppetlabs/puppet/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/puppetlabs/puppet/labels{/name}","releases_url":"https://api.github.com/repos/puppetlabs/puppet/releases{/id}","deployments_url":"https://api.github.com/repos/puppetlabs/puppet/deployments","created_at":"2010-09-14T19:26:44Z","updated_at":"2016-05-01T16:25:36Z","pushed_at":"2016-05-01T02:55:16Z","git_url":"git://github.com/puppetlabs/puppet.git","ssh_url":"git@github.com:puppetlabs/puppet.git","clone_url":"https://github.com/puppetlabs/puppet.git","svn_url":"https://github.com/puppetlabs/puppet","homepage":"https://puppetlabs.com/puppet/what-is-puppet","size":80124,"stargazers_count":3963,"watchers_count":3963,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1627,"mirror_url":null,"open_issues_count":35,"forks":1627,"open_issues":35,"watchers":3963,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/puppetlabs/puppet/pulls/4927"},"html":{"href":"https://github.com/puppetlabs/puppet/pull/4927"},"issue":{"href":"https://api.github.com/repos/puppetlabs/puppet/issues/4927"},"comments":{"href":"https://api.github.com/repos/puppetlabs/puppet/issues/4927/comments"},"review_comments":{"href":"https://api.github.com/repos/puppetlabs/puppet/pulls/4927/comments"},"review_comment":{"href":"https://api.github.com/repos/puppetlabs/puppet/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/puppetlabs/puppet/pulls/4927/commits"},"statuses":{"href":"https://api.github.com/repos/puppetlabs/puppet/statuses/0066a2087f3ed2fd1043e7b37efb758ee397b94d"}}}}