{"action":"created","comment":{"url":"https://api.github.com/repos/roqua/quby_engine/pulls/comments/48013114","id":48013114,"diff_hunk":"@@ -0,0 +1,111 @@\n+require 'quby/answers/entities/table_backend/table_dimension'\n+module Quby::Answers::Entities::TableBackend\n+  class DiskTable\n+    require \"pathname\"\n+\n+    def self.disk_table_root\n+      fail 'Quby.lookup_table_path not configured' if Quby.lookup_table_path.blank?\n+      Quby.lookup_table_path\n+    end\n+\n+    def self.validate_jailed_path(path)\n+      full_path = File.expand_path(path)\n+      jail = File.expand_path(disk_table_root)\n+      full_path.starts_with?(jail)\n+    end\n+\n+    # range should either be:\n+    #  a 2 long float string array, these will be converted into a float range\n+    #    float ranges will be open ended on the right side\n+    #  a varied length non-float string array, to signify a set of categorical options (like 'male', 'female', 'other')\n+    #    this will be returned as is\n+    #  an empty array, which returns a range that will accept any value on an 'include?' call\n+    def self.parse_range(range)\n+      maybe_float_start = parse_float(range.first)\n+      if maybe_float_start.present?\n+        maybe_float_end = parse_float(range[1])\n+        if maybe_float_end.present? && range.length == 2\n+          return (maybe_float_start...maybe_float_end)\n+        else\n+          fail \"#{range} has a float start but not a float end\"\n+        end\n+      else # categorical range ([strings] that need no parsing), or empty array (which means 'accept anything')\n+        if range.length >= 1\n+          return range\n+        else\n+          return Quby::Answers::Entities::TableBackend::TableDimension::AcceptsAnythingRange.instance\n+        end\n+      end\n+    end\n+\n+    def self.parse_float(maybe_float_string)\n+      maybe_float = Float(maybe_float_string) rescue nil # can you strictly parse without using exceptions?\n+      case maybe_float_string\n+      when 'minfinity'\n+        maybe_float = -Float::INFINITY\n+      when 'infinity'\n+        maybe_float = Float::INFINITY\n+      end\n+\n+      maybe_float\n+    end\n+\n+    def initialize(key)\n+      path = Pathname.new self.class.disk_table_root.join(key)\n+      fail \"path #{path} outside of jail\" unless self.class.validate_jailed_path(path)\n+\n+      @root_dimensions = dimensions_from_children(path)\n+    end\n+\n+    def lookup(parameters)\n+      result = nil\n+      @root_dimensions.find do |dimension|\n+        result = dimension.lookup(parameters)\n+      end\n+      result\n+    end\n+\n+    def dimensions_from_children(directory_path)\n+      children = Pathname.new(directory_path).children\n+\n+      # directory names are of the form 'dimensionname_rangestart_rangeend',\n+      # files use the whole name as the dimension name, so we can use underscores in leaf dimension names\n+      if children.all?(&:directory?)\n+        dimensions_from_directories children\n+      else\n+        dimensions_from_files children\n+      end\n+    end\n+\n+    def dimensions_from_directories(directory_names)\n+      dimensions = directory_names.group_by do |child|\n+        child.expand_path.basename.to_s.split('_').first\n+      end\n+\n+      dimensions.map do |dimension_key, pathnames|\n+        ranges = pathnames.map do |pathname|\n+          range_key = self.class.parse_range pathname.expand_path.basename.to_s.split('_')[1..-1]\n+          range_value = dimensions_from_children(pathname)\n+\n+          [range_key, range_value]\n+        end.to_h\n+\n+        TableDimension.new(dimension_key, ranges)\n+      end\n+    end\n+\n+    def dimensions_from_files(file_names)","path":"lib/quby/answers/entities/table_backend/disk_table.rb","position":97,"original_position":97,"commit_id":"54bb89cf5586d6854dc0a88ad6a2f084d375d2eb","original_commit_id":"54bb89cf5586d6854dc0a88ad6a2f084d375d2eb","user":{"login":"hampei","id":18834,"avatar_url":"https://avatars.githubusercontent.com/u/18834?v=3","gravatar_id":"","url":"https://api.github.com/users/hampei","html_url":"https://github.com/hampei","followers_url":"https://api.github.com/users/hampei/followers","following_url":"https://api.github.com/users/hampei/following{/other_user}","gists_url":"https://api.github.com/users/hampei/gists{/gist_id}","starred_url":"https://api.github.com/users/hampei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hampei/subscriptions","organizations_url":"https://api.github.com/users/hampei/orgs","repos_url":"https://api.github.com/users/hampei/repos","events_url":"https://api.github.com/users/hampei/events{/privacy}","received_events_url":"https://api.github.com/users/hampei/received_events","type":"User","site_admin":false},"body":"Ik verwacht strings in een file_names variabele.\r\nfile_paths of file_path_names ?","created_at":"2015-12-18T10:37:33Z","updated_at":"2015-12-18T10:37:33Z","html_url":"https://github.com/roqua/quby_engine/pull/138#discussion_r48013114","pull_request_url":"https://api.github.com/repos/roqua/quby_engine/pulls/138","_links":{"self":{"href":"https://api.github.com/repos/roqua/quby_engine/pulls/comments/48013114"},"html":{"href":"https://github.com/roqua/quby_engine/pull/138#discussion_r48013114"},"pull_request":{"href":"https://api.github.com/repos/roqua/quby_engine/pulls/138"}}},"pull_request":{"url":"https://api.github.com/repos/roqua/quby_engine/pulls/138","id":53995000,"html_url":"https://github.com/roqua/quby_engine/pull/138","diff_url":"https://github.com/roqua/quby_engine/pull/138.diff","patch_url":"https://github.com/roqua/quby_engine/pull/138.patch","issue_url":"https://api.github.com/repos/roqua/quby_engine/issues/138","number":138,"state":"open","locked":false,"title":"Lookup tables","user":{"login":"jornvandebeek","id":123905,"avatar_url":"https://avatars.githubusercontent.com/u/123905?v=3","gravatar_id":"","url":"https://api.github.com/users/jornvandebeek","html_url":"https://github.com/jornvandebeek","followers_url":"https://api.github.com/users/jornvandebeek/followers","following_url":"https://api.github.com/users/jornvandebeek/following{/other_user}","gists_url":"https://api.github.com/users/jornvandebeek/gists{/gist_id}","starred_url":"https://api.github.com/users/jornvandebeek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jornvandebeek/subscriptions","organizations_url":"https://api.github.com/users/jornvandebeek/orgs","repos_url":"https://api.github.com/users/jornvandebeek/repos","events_url":"https://api.github.com/users/jornvandebeek/events{/privacy}","received_events_url":"https://api.github.com/users/jornvandebeek/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-12-17T16:04:48Z","updated_at":"2015-12-18T10:37:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dedec1855f5571b9699539026ed48b71a498629d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/roqua/quby_engine/pulls/138/commits","review_comments_url":"https://api.github.com/repos/roqua/quby_engine/pulls/138/comments","review_comment_url":"https://api.github.com/repos/roqua/quby_engine/pulls/comments{/number}","comments_url":"https://api.github.com/repos/roqua/quby_engine/issues/138/comments","statuses_url":"https://api.github.com/repos/roqua/quby_engine/statuses/54bb89cf5586d6854dc0a88ad6a2f084d375d2eb","head":{"label":"roqua:jb_lookup_table","ref":"jb_lookup_table","sha":"54bb89cf5586d6854dc0a88ad6a2f084d375d2eb","user":{"login":"roqua","id":598697,"avatar_url":"https://avatars.githubusercontent.com/u/598697?v=3","gravatar_id":"","url":"https://api.github.com/users/roqua","html_url":"https://github.com/roqua","followers_url":"https://api.github.com/users/roqua/followers","following_url":"https://api.github.com/users/roqua/following{/other_user}","gists_url":"https://api.github.com/users/roqua/gists{/gist_id}","starred_url":"https://api.github.com/users/roqua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roqua/subscriptions","organizations_url":"https://api.github.com/users/roqua/orgs","repos_url":"https://api.github.com/users/roqua/repos","events_url":"https://api.github.com/users/roqua/events{/privacy}","received_events_url":"https://api.github.com/users/roqua/received_events","type":"Organization","site_admin":false},"repo":{"id":4905239,"name":"quby_engine","full_name":"roqua/quby_engine","owner":{"login":"roqua","id":598697,"avatar_url":"https://avatars.githubusercontent.com/u/598697?v=3","gravatar_id":"","url":"https://api.github.com/users/roqua","html_url":"https://github.com/roqua","followers_url":"https://api.github.com/users/roqua/followers","following_url":"https://api.github.com/users/roqua/following{/other_user}","gists_url":"https://api.github.com/users/roqua/gists{/gist_id}","starred_url":"https://api.github.com/users/roqua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roqua/subscriptions","organizations_url":"https://api.github.com/users/roqua/orgs","repos_url":"https://api.github.com/users/roqua/repos","events_url":"https://api.github.com/users/roqua/events{/privacy}","received_events_url":"https://api.github.com/users/roqua/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/roqua/quby_engine","description":"Rails Engine to let people edit answers for questionnaires","fork":false,"url":"https://api.github.com/repos/roqua/quby_engine","forks_url":"https://api.github.com/repos/roqua/quby_engine/forks","keys_url":"https://api.github.com/repos/roqua/quby_engine/keys{/key_id}","collaborators_url":"https://api.github.com/repos/roqua/quby_engine/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/roqua/quby_engine/teams","hooks_url":"https://api.github.com/repos/roqua/quby_engine/hooks","issue_events_url":"https://api.github.com/repos/roqua/quby_engine/issues/events{/number}","events_url":"https://api.github.com/repos/roqua/quby_engine/events","assignees_url":"https://api.github.com/repos/roqua/quby_engine/assignees{/user}","branches_url":"https://api.github.com/repos/roqua/quby_engine/branches{/branch}","tags_url":"https://api.github.com/repos/roqua/quby_engine/tags","blobs_url":"https://api.github.com/repos/roqua/quby_engine/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/roqua/quby_engine/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/roqua/quby_engine/git/refs{/sha}","trees_url":"https://api.github.com/repos/roqua/quby_engine/git/trees{/sha}","statuses_url":"https://api.github.com/repos/roqua/quby_engine/statuses/{sha}","languages_url":"https://api.github.com/repos/roqua/quby_engine/languages","stargazers_url":"https://api.github.com/repos/roqua/quby_engine/stargazers","contributors_url":"https://api.github.com/repos/roqua/quby_engine/contributors","subscribers_url":"https://api.github.com/repos/roqua/quby_engine/subscribers","subscription_url":"https://api.github.com/repos/roqua/quby_engine/subscription","commits_url":"https://api.github.com/repos/roqua/quby_engine/commits{/sha}","git_commits_url":"https://api.github.com/repos/roqua/quby_engine/git/commits{/sha}","comments_url":"https://api.github.com/repos/roqua/quby_engine/comments{/number}","issue_comment_url":"https://api.github.com/repos/roqua/quby_engine/issues/comments{/number}","contents_url":"https://api.github.com/repos/roqua/quby_engine/contents/{+path}","compare_url":"https://api.github.com/repos/roqua/quby_engine/compare/{base}...{head}","merges_url":"https://api.github.com/repos/roqua/quby_engine/merges","archive_url":"https://api.github.com/repos/roqua/quby_engine/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/roqua/quby_engine/downloads","issues_url":"https://api.github.com/repos/roqua/quby_engine/issues{/number}","pulls_url":"https://api.github.com/repos/roqua/quby_engine/pulls{/number}","milestones_url":"https://api.github.com/repos/roqua/quby_engine/milestones{/number}","notifications_url":"https://api.github.com/repos/roqua/quby_engine/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/roqua/quby_engine/labels{/name}","releases_url":"https://api.github.com/repos/roqua/quby_engine/releases{/id}","created_at":"2012-07-05T12:01:01Z","updated_at":"2015-05-04T15:48:34Z","pushed_at":"2015-12-18T07:42:39Z","git_url":"git://github.com/roqua/quby_engine.git","ssh_url":"git@github.com:roqua/quby_engine.git","clone_url":"https://github.com/roqua/quby_engine.git","svn_url":"https://github.com/roqua/quby_engine","homepage":null,"size":13410,"stargazers_count":2,"watchers_count":2,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":5,"forks":1,"open_issues":5,"watchers":2,"default_branch":"master"}},"base":{"label":"roqua:master","ref":"master","sha":"f09a24b05277f554225404cafe673b95a7ace97b","user":{"login":"roqua","id":598697,"avatar_url":"https://avatars.githubusercontent.com/u/598697?v=3","gravatar_id":"","url":"https://api.github.com/users/roqua","html_url":"https://github.com/roqua","followers_url":"https://api.github.com/users/roqua/followers","following_url":"https://api.github.com/users/roqua/following{/other_user}","gists_url":"https://api.github.com/users/roqua/gists{/gist_id}","starred_url":"https://api.github.com/users/roqua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roqua/subscriptions","organizations_url":"https://api.github.com/users/roqua/orgs","repos_url":"https://api.github.com/users/roqua/repos","events_url":"https://api.github.com/users/roqua/events{/privacy}","received_events_url":"https://api.github.com/users/roqua/received_events","type":"Organization","site_admin":false},"repo":{"id":4905239,"name":"quby_engine","full_name":"roqua/quby_engine","owner":{"login":"roqua","id":598697,"avatar_url":"https://avatars.githubusercontent.com/u/598697?v=3","gravatar_id":"","url":"https://api.github.com/users/roqua","html_url":"https://github.com/roqua","followers_url":"https://api.github.com/users/roqua/followers","following_url":"https://api.github.com/users/roqua/following{/other_user}","gists_url":"https://api.github.com/users/roqua/gists{/gist_id}","starred_url":"https://api.github.com/users/roqua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roqua/subscriptions","organizations_url":"https://api.github.com/users/roqua/orgs","repos_url":"https://api.github.com/users/roqua/repos","events_url":"https://api.github.com/users/roqua/events{/privacy}","received_events_url":"https://api.github.com/users/roqua/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/roqua/quby_engine","description":"Rails Engine to let people edit answers for questionnaires","fork":false,"url":"https://api.github.com/repos/roqua/quby_engine","forks_url":"https://api.github.com/repos/roqua/quby_engine/forks","keys_url":"https://api.github.com/repos/roqua/quby_engine/keys{/key_id}","collaborators_url":"https://api.github.com/repos/roqua/quby_engine/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/roqua/quby_engine/teams","hooks_url":"https://api.github.com/repos/roqua/quby_engine/hooks","issue_events_url":"https://api.github.com/repos/roqua/quby_engine/issues/events{/number}","events_url":"https://api.github.com/repos/roqua/quby_engine/events","assignees_url":"https://api.github.com/repos/roqua/quby_engine/assignees{/user}","branches_url":"https://api.github.com/repos/roqua/quby_engine/branches{/branch}","tags_url":"https://api.github.com/repos/roqua/quby_engine/tags","blobs_url":"https://api.github.com/repos/roqua/quby_engine/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/roqua/quby_engine/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/roqua/quby_engine/git/refs{/sha}","trees_url":"https://api.github.com/repos/roqua/quby_engine/git/trees{/sha}","statuses_url":"https://api.github.com/repos/roqua/quby_engine/statuses/{sha}","languages_url":"https://api.github.com/repos/roqua/quby_engine/languages","stargazers_url":"https://api.github.com/repos/roqua/quby_engine/stargazers","contributors_url":"https://api.github.com/repos/roqua/quby_engine/contributors","subscribers_url":"https://api.github.com/repos/roqua/quby_engine/subscribers","subscription_url":"https://api.github.com/repos/roqua/quby_engine/subscription","commits_url":"https://api.github.com/repos/roqua/quby_engine/commits{/sha}","git_commits_url":"https://api.github.com/repos/roqua/quby_engine/git/commits{/sha}","comments_url":"https://api.github.com/repos/roqua/quby_engine/comments{/number}","issue_comment_url":"https://api.github.com/repos/roqua/quby_engine/issues/comments{/number}","contents_url":"https://api.github.com/repos/roqua/quby_engine/contents/{+path}","compare_url":"https://api.github.com/repos/roqua/quby_engine/compare/{base}...{head}","merges_url":"https://api.github.com/repos/roqua/quby_engine/merges","archive_url":"https://api.github.com/repos/roqua/quby_engine/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/roqua/quby_engine/downloads","issues_url":"https://api.github.com/repos/roqua/quby_engine/issues{/number}","pulls_url":"https://api.github.com/repos/roqua/quby_engine/pulls{/number}","milestones_url":"https://api.github.com/repos/roqua/quby_engine/milestones{/number}","notifications_url":"https://api.github.com/repos/roqua/quby_engine/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/roqua/quby_engine/labels{/name}","releases_url":"https://api.github.com/repos/roqua/quby_engine/releases{/id}","created_at":"2012-07-05T12:01:01Z","updated_at":"2015-05-04T15:48:34Z","pushed_at":"2015-12-18T07:42:39Z","git_url":"git://github.com/roqua/quby_engine.git","ssh_url":"git@github.com:roqua/quby_engine.git","clone_url":"https://github.com/roqua/quby_engine.git","svn_url":"https://github.com/roqua/quby_engine","homepage":null,"size":13410,"stargazers_count":2,"watchers_count":2,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":5,"forks":1,"open_issues":5,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/roqua/quby_engine/pulls/138"},"html":{"href":"https://github.com/roqua/quby_engine/pull/138"},"issue":{"href":"https://api.github.com/repos/roqua/quby_engine/issues/138"},"comments":{"href":"https://api.github.com/repos/roqua/quby_engine/issues/138/comments"},"review_comments":{"href":"https://api.github.com/repos/roqua/quby_engine/pulls/138/comments"},"review_comment":{"href":"https://api.github.com/repos/roqua/quby_engine/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/roqua/quby_engine/pulls/138/commits"},"statuses":{"href":"https://api.github.com/repos/roqua/quby_engine/statuses/54bb89cf5586d6854dc0a88ad6a2f084d375d2eb"}}}}