hqmf2js 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -3
- data/Gemfile.lock +33 -22
- data/app/assets/javascripts/custom_calculations.js.coffee +63 -5
- data/app/assets/javascripts/hqmf_util.js.coffee +38 -5
- data/app/assets/javascripts/logging_utils.js.coffee +15 -8
- data/app/assets/javascripts/patient_api_extension.js.coffee +4 -0
- data/hqmf2js.gemspec +3 -1
- data/lib/generator/codes_to_json.rb +5 -4
- data/lib/generator/data_criteria.js.erb +2 -2
- data/lib/generator/derived_data.js.erb +1 -1
- data/lib/generator/js.rb +8 -3
- data/lib/generator/measure_period.js.erb +2 -1
- data/lib/generator/observation_criteria.js.erb +4 -0
- data/lib/generator/population_criteria.js.erb +2 -2
- data/lib/generator/precondition.js.erb +5 -3
- data/lib/tasks/convert.rake +13 -9
- data/test/fixtures/json/59New.json +3 -3
- data/test/fixtures/patients/larry_vanderman.json +1 -1
- data/test/unit/custom_calculations_test.rb +66 -0
- data/test/unit/library_function_test.rb +16 -16
- data/test/unit/specifics_test.rb +23 -0
- metadata +35 -2
    
        data/Gemfile
    CHANGED
    
    
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,3 +1,14 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: .
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                hqmf2js (1.2.0)
         | 
| 5 | 
            +
                  coffee-script (~> 2.2.0)
         | 
| 6 | 
            +
                  health-data-standards (~> 3.0.1)
         | 
| 7 | 
            +
                  hquery-patient-api (~> 1.0.1)
         | 
| 8 | 
            +
                  nokogiri (~> 1.5.5)
         | 
| 9 | 
            +
                  sprockets (~> 2.2.2)
         | 
| 10 | 
            +
                  tilt (~> 1.3.3)
         | 
| 11 | 
            +
             | 
| 1 12 | 
             
            GEM
         | 
| 2 13 | 
             
              remote: http://rubygems.org/
         | 
| 3 14 | 
             
              specs:
         | 
| @@ -49,28 +60,28 @@ GEM | |
| 49 60 | 
             
                erubis (2.7.0)
         | 
| 50 61 | 
             
                execjs (1.4.0)
         | 
| 51 62 | 
             
                  multi_json (~> 1.0)
         | 
| 52 | 
            -
                faraday (0.8. | 
| 63 | 
            +
                faraday (0.8.6)
         | 
| 53 64 | 
             
                  multipart-post (~> 1.1)
         | 
| 54 65 | 
             
                google-spreadsheet-ruby (0.1.8)
         | 
| 55 66 | 
             
                  nokogiri (>= 1.4.3.1)
         | 
| 56 67 | 
             
                  oauth (>= 0.3.6)
         | 
| 57 68 | 
             
                  oauth2 (>= 0.5.0)
         | 
| 58 69 | 
             
                hashie (1.2.0)
         | 
| 59 | 
            -
                health-data-standards ( | 
| 70 | 
            +
                health-data-standards (3.0.1)
         | 
| 60 71 | 
             
                  activesupport (~> 3.2.9)
         | 
| 61 72 | 
             
                  builder (~> 3.0.0)
         | 
| 62 73 | 
             
                  erubis (~> 2.7.0)
         | 
| 63 | 
            -
                   | 
| 74 | 
            +
                  google-spreadsheet-ruby (= 0.1.8)
         | 
| 75 | 
            +
                  log4r (~> 1.1.10)
         | 
| 76 | 
            +
                  mongoid (~> 3.1.0)
         | 
| 64 77 | 
             
                  nokogiri (~> 1.5.5)
         | 
| 65 78 | 
             
                  rest-client (~> 1.6.7)
         | 
| 66 | 
            -
                  uuid (~> 2.3.5)
         | 
| 67 | 
            -
                hike (1.2.1)
         | 
| 68 | 
            -
                hqmf-parser (1.1.0)
         | 
| 69 | 
            -
                  google-spreadsheet-ruby (= 0.1.8)
         | 
| 70 79 | 
             
                  roo (= 1.10.1)
         | 
| 71 80 | 
             
                  rubyzip
         | 
| 72 81 | 
             
                  spreadsheet (= 0.6.8)
         | 
| 73 | 
            -
             | 
| 82 | 
            +
                  uuid (~> 2.3.5)
         | 
| 83 | 
            +
                hike (1.2.1)
         | 
| 84 | 
            +
                hquery-patient-api (1.0.1)
         | 
| 74 85 | 
             
                httpauth (0.2.0)
         | 
| 75 86 | 
             
                i18n (0.6.1)
         | 
| 76 87 | 
             
                journey (1.0.4)
         | 
| @@ -86,23 +97,25 @@ GEM | |
| 86 97 | 
             
                  mime-types (~> 1.16)
         | 
| 87 98 | 
             
                  treetop (~> 1.4.8)
         | 
| 88 99 | 
             
                method_source (0.8.1)
         | 
| 89 | 
            -
                mime-types (1. | 
| 100 | 
            +
                mime-types (1.20.1)
         | 
| 90 101 | 
             
                minitest (4.3.2)
         | 
| 91 | 
            -
                mongoid (3. | 
| 92 | 
            -
                  activemodel (~> 3. | 
| 93 | 
            -
                  moped (~> 1. | 
| 102 | 
            +
                mongoid (3.1.2)
         | 
| 103 | 
            +
                  activemodel (~> 3.2)
         | 
| 104 | 
            +
                  moped (~> 1.4.2)
         | 
| 94 105 | 
             
                  origin (~> 1.0)
         | 
| 95 106 | 
             
                  tzinfo (~> 0.3.22)
         | 
| 96 | 
            -
                moped (1. | 
| 97 | 
            -
                multi_json (1. | 
| 98 | 
            -
                 | 
| 99 | 
            -
                 | 
| 107 | 
            +
                moped (1.4.2)
         | 
| 108 | 
            +
                multi_json (1.5.0)
         | 
| 109 | 
            +
                multi_xml (0.5.3)
         | 
| 110 | 
            +
                multipart-post (1.2.0)
         | 
| 111 | 
            +
                nokogiri (1.5.6)
         | 
| 100 112 | 
             
                oauth (0.4.7)
         | 
| 101 | 
            -
                oauth2 (0. | 
| 113 | 
            +
                oauth2 (0.9.1)
         | 
| 102 114 | 
             
                  faraday (~> 0.8)
         | 
| 103 115 | 
             
                  httpauth (~> 0.1)
         | 
| 104 116 | 
             
                  jwt (~> 0.1.4)
         | 
| 105 117 | 
             
                  multi_json (~> 1.0)
         | 
| 118 | 
            +
                  multi_xml (~> 0.5)
         | 
| 106 119 | 
             
                  rack (~> 1.2)
         | 
| 107 120 | 
             
                origin (1.0.11)
         | 
| 108 121 | 
             
                polyglot (0.3.3)
         | 
| @@ -110,7 +123,7 @@ GEM | |
| 110 123 | 
             
                  coderay (~> 1.0.5)
         | 
| 111 124 | 
             
                  method_source (~> 0.8)
         | 
| 112 125 | 
             
                  slop (~> 3.3.1)
         | 
| 113 | 
            -
                rack (1.4. | 
| 126 | 
            +
                rack (1.4.4)
         | 
| 114 127 | 
             
                rack-cache (1.2)
         | 
| 115 128 | 
             
                  rack (>= 0.4)
         | 
| 116 129 | 
             
                rack-ssl (1.3.2)
         | 
| @@ -175,7 +188,7 @@ GEM | |
| 175 188 | 
             
                uglifier (1.3.0)
         | 
| 176 189 | 
             
                  execjs (>= 0.3.0)
         | 
| 177 190 | 
             
                  multi_json (~> 1.0, >= 1.0.2)
         | 
| 178 | 
            -
                uuid (2.3. | 
| 191 | 
            +
                uuid (2.3.7)
         | 
| 179 192 | 
             
                  macaddr (~> 1.0)
         | 
| 180 193 | 
             
                yamler (0.1.0)
         | 
| 181 194 |  | 
| @@ -187,9 +200,7 @@ DEPENDENCIES | |
| 187 200 | 
             
              coffee-rails
         | 
| 188 201 | 
             
              coffee-script
         | 
| 189 202 | 
             
              cover_me (~> 1.2.0)
         | 
| 190 | 
            -
               | 
| 191 | 
            -
              hqmf-parser (~> 1.1.0)
         | 
| 192 | 
            -
              hquery-patient-api (~> 1.0.0)
         | 
| 203 | 
            +
              hqmf2js!
         | 
| 193 204 | 
             
              minitest
         | 
| 194 205 | 
             
              nokogiri
         | 
| 195 206 | 
             
              pry
         | 
| @@ -1,16 +1,74 @@ | |
| 1 1 | 
             
            @hqmf.CustomCalc = {}
         | 
| 2 2 |  | 
| 3 | 
            +
            @hqmf.CustomCalc.ADE_TTR_OBSERV = (patient, hqmfjs) ->
         | 
| 4 | 
            +
              inrReadings = DURING(hqmfjs.LaboratoryTestResultInr(patient), hqmfjs.MeasurePeriod(patient));
         | 
| 5 | 
            +
              inrReadings = new hqmf.CustomCalc.PercentTTREntries(inrReadings)
         | 
| 6 | 
            +
              [inrReadings.calculatePercentTTR()]
         | 
| 7 | 
            +
             | 
| 3 8 | 
             
            class @hqmf.CustomCalc.PercentTTREntries extends hQuery.CodedEntryList
         | 
| 4 9 |  | 
| 5 10 | 
             
              constructor: (events) ->
         | 
| 6 11 | 
             
                super()
         | 
| 7 | 
            -
                events = events.sort(dateSortAscending)
         | 
| 8 | 
            -
                @push(event) for event in events
         | 
| 9 12 | 
             
                @minInr = 2.0
         | 
| 10 13 | 
             
                @maxInr = 3.0
         | 
| 11 | 
            -
                 | 
| 12 | 
            -
                 | 
| 13 | 
            -
                 | 
| 14 | 
            +
                @minOutOfRange = 0.8
         | 
| 15 | 
            +
                @maxOutOfRange = 10
         | 
| 16 | 
            +
                @closestSetpoint = 2.5
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                clonedEvents = []
         | 
| 19 | 
            +
                clonedEvents.push(new event.constructor(event.json)) for event in events
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                # remove entries < 0.8
         | 
| 22 | 
            +
                # reset > 10 to be 10
         | 
| 23 | 
            +
                # remove duplicate results on entries to those closest to 2.5
         | 
| 24 | 
            +
                for entry in clonedEvents
         | 
| 25 | 
            +
                  currentClosestValue = null
         | 
| 26 | 
            +
                  for value in entry.values()
         | 
| 27 | 
            +
                    if value.scalar() > @maxOutOfRange
         | 
| 28 | 
            +
                      value.json['scalar'] = '10.0'
         | 
| 29 | 
            +
                    if value.scalar() >= @minOutOfRange && value.scalar() <= @maxOutOfRange
         | 
| 30 | 
            +
                      currentClosestValue = @closestValueToSetpoint(currentClosestValue, value)
         | 
| 31 | 
            +
                  
         | 
| 32 | 
            +
                  passingValues = []
         | 
| 33 | 
            +
                  passingValues = [currentClosestValue.json] if currentClosestValue?
         | 
| 34 | 
            +
                  entry.json['values'] = passingValues
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # filter duplicates to those closest to 2.5 on the same day
         | 
| 37 | 
            +
                # remove any entries with no values (removed because the value was below 0.8, or no value on source data)
         | 
| 38 | 
            +
                entriesByDay = {}
         | 
| 39 | 
            +
                for entry in clonedEvents
         | 
| 40 | 
            +
                  date = entry.timeStamp()
         | 
| 41 | 
            +
                  key = "#{date.getUTCFullYear()}_#{date.getUTCMonth()}_#{date.getUTCDate()}"
         | 
| 42 | 
            +
                  entriesByDay[key] = [] unless entriesByDay[key]
         | 
| 43 | 
            +
                  entriesByDay[key].push(entry) if entry.values().length > 0
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                # keep the closest entry to 2.5 when there are multiple entries per day
         | 
| 46 | 
            +
                finalEvents = []
         | 
| 47 | 
            +
                for key in _.keys(entriesByDay)
         | 
| 48 | 
            +
                  if (entriesByDay[key].length > 1)
         | 
| 49 | 
            +
                    currentClosestValue = null
         | 
| 50 | 
            +
                    selectedEntry = null
         | 
| 51 | 
            +
                    for entry in entriesByDay[key]
         | 
| 52 | 
            +
                      currentClosestValue = @closestValueToSetpoint(currentClosestValue, entry.values()[0])
         | 
| 53 | 
            +
                      if currentClosestValue.scalar() == entry.values()[0].scalar()
         | 
| 54 | 
            +
                        selectedEntry = entry
         | 
| 55 | 
            +
                    finalEvents.push(selectedEntry)
         | 
| 56 | 
            +
                  else
         | 
| 57 | 
            +
                    finalEvents = finalEvents.concat(entriesByDay[key])
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                finalEvents = finalEvents.sort(dateSortAscending)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                @push(event) for event in finalEvents
         | 
| 62 | 
            +
             | 
| 63 | 
            +
             | 
| 64 | 
            +
              closestValueToSetpoint: (one, two) ->
         | 
| 65 | 
            +
                return two if one == null
         | 
| 66 | 
            +
                return one if two == null
         | 
| 67 | 
            +
                if (Math.abs(one.scalar() - @closestSetpoint) > Math.abs(two.scalar() - @closestSetpoint))
         | 
| 68 | 
            +
                  return two
         | 
| 69 | 
            +
                else
         | 
| 70 | 
            +
                  return one
         | 
| 71 | 
            +
             | 
| 14 72 |  | 
| 15 73 | 
             
              calculateDaysInRange: (firstInr, secondInr) ->
         | 
| 16 74 |  | 
| @@ -408,26 +408,26 @@ class ANYNonNull | |
| 408 408 | 
             
            @ANYNonNull = ANYNonNull
         | 
| 409 409 |  | 
| 410 410 | 
             
            # Returns true if one or more of the supplied values is true
         | 
| 411 | 
            -
            atLeastOneTrue = (values...) ->
         | 
| 411 | 
            +
            atLeastOneTrue = (precondition, values...) ->
         | 
| 412 412 | 
             
              trueValues = (value for value in values when value && value.isTrue())
         | 
| 413 413 | 
             
              trueValues.length>0
         | 
| 414 414 | 
             
              hqmf.SpecificsManager.unionAll(new Boolean(trueValues.length>0), values)
         | 
| 415 415 | 
             
            @atLeastOneTrue = atLeastOneTrue
         | 
| 416 416 |  | 
| 417 417 | 
             
            # Returns true if all of the supplied values are true
         | 
| 418 | 
            -
            allTrue = (values...) ->
         | 
| 418 | 
            +
            allTrue = (precondition, values...) ->
         | 
| 419 419 | 
             
              trueValues = (value for value in values when value && value.isTrue())
         | 
| 420 420 | 
             
              hqmf.SpecificsManager.intersectAll(new Boolean(trueValues.length>0 && trueValues.length==values.length), values)
         | 
| 421 421 | 
             
            @allTrue = allTrue
         | 
| 422 422 |  | 
| 423 423 | 
             
            # Returns true if one or more of the supplied values is false
         | 
| 424 | 
            -
            atLeastOneFalse = (values...) ->
         | 
| 424 | 
            +
            atLeastOneFalse = (precondition, values...) ->
         | 
| 425 425 | 
             
              falseValues = (value for value in values when value.isFalse())
         | 
| 426 426 | 
             
              hqmf.SpecificsManager.intersectAll(new Boolean(falseValues.length>0), values, true)
         | 
| 427 427 | 
             
            @atLeastOneFalse = atLeastOneFalse
         | 
| 428 428 |  | 
| 429 429 | 
             
            # Returns true if all of the supplied values are false
         | 
| 430 | 
            -
            allFalse = (values...) ->
         | 
| 430 | 
            +
            allFalse = (precondition, values...) ->
         | 
| 431 431 | 
             
              falseValues = (value for value in values when value.isFalse())
         | 
| 432 432 | 
             
              hqmf.SpecificsManager.unionAll(new Boolean(falseValues.length>0 && falseValues.length==values.length), values, true)
         | 
| 433 433 | 
             
            @allFalse = allFalse
         | 
| @@ -514,6 +514,8 @@ class CrossProduct extends Array | |
| 514 514 | 
             
                  @eventLists.push eventList
         | 
| 515 515 | 
             
                  for event in eventList
         | 
| 516 516 | 
             
                    this.push(event)
         | 
| 517 | 
            +
              listCount: -> @eventLists.length
         | 
| 518 | 
            +
              childList: (index) -> @eventLists[index]
         | 
| 517 519 |  | 
| 518 520 | 
             
            # Create a CrossProduct of the supplied event lists.
         | 
| 519 521 | 
             
            XPRODUCT = (eventLists...) ->
         | 
| @@ -545,7 +547,7 @@ getIVL = (eventOrTimeStamp) -> | |
| 545 547 | 
             
                ts.date = eventOrTimeStamp
         | 
| 546 548 | 
             
                new IVL_TS(ts, ts)
         | 
| 547 549 | 
             
            @getIVL = getIVL
         | 
| 548 | 
            -
             | 
| 550 | 
            +
             | 
| 549 551 | 
             
            eventAccessor = {  
         | 
| 550 552 | 
             
              'DURING': 'low',
         | 
| 551 553 | 
             
              'OVERLAP': 'low',
         | 
| @@ -820,6 +822,37 @@ DATEDIFF = (events, range) -> | |
| 820 822 | 
             
              hqmf.SpecificsManager.maintainSpecifics(new Boolean(withinRange('DATEDIFF', getIVL(events[0]), getIVL(events[1]), range)), events)
         | 
| 821 823 | 
             
            @DATEDIFF = DATEDIFF
         | 
| 822 824 |  | 
| 825 | 
            +
            # Calculate the set of time differences in minutes between pairs of events
         | 
| 826 | 
            +
            # events - a XPRODUCT of two event lists
         | 
| 827 | 
            +
            # range - ignored
         | 
| 828 | 
            +
            # initialSpecificContext - the specific context containing one row per permissible
         | 
| 829 | 
            +
            # combination of events
         | 
| 830 | 
            +
            TIMEDIFF = (events, range, initialSpecificContext) ->
         | 
| 831 | 
            +
              if events.listCount() != 2
         | 
| 832 | 
            +
                throw "TIMEDIFF can only process 2 lists of events"
         | 
| 833 | 
            +
              eventList1 = events.childList(0)
         | 
| 834 | 
            +
              eventList2 = events.childList(1)
         | 
| 835 | 
            +
              eventIndex1 = hqmf.SpecificsManager.getColumnIndex(eventList1.specific_occurrence)
         | 
| 836 | 
            +
              eventIndex2 = hqmf.SpecificsManager.getColumnIndex(eventList2.specific_occurrence)
         | 
| 837 | 
            +
              eventMap1 = {}
         | 
| 838 | 
            +
              eventMap2 = {}
         | 
| 839 | 
            +
              for event in eventList1
         | 
| 840 | 
            +
                eventMap1[event.id] = event
         | 
| 841 | 
            +
              for event in eventList2
         | 
| 842 | 
            +
                eventMap2[event.id] = event
         | 
| 843 | 
            +
              results = []
         | 
| 844 | 
            +
              for row in initialSpecificContext.rows
         | 
| 845 | 
            +
                event1 = row.values[eventIndex1]
         | 
| 846 | 
            +
                event2 = row.values[eventIndex2]
         | 
| 847 | 
            +
                if event1 and event2 and event1 != hqmf.SpecificsManager.any and event2 != hqmf.SpecificsManager.any 
         | 
| 848 | 
            +
                  # The maps contain the actual events we want to work with since these may contain
         | 
| 849 | 
            +
                  # time shifted clones of the events in the specificContext, e.g. via adjustBoundsForField
         | 
| 850 | 
            +
                  shiftedEvent1 = eventMap1[event1.id]
         | 
| 851 | 
            +
                  shiftedEvent2 = eventMap2[event2.id]
         | 
| 852 | 
            +
                  if shiftedEvent1 and shiftedEvent2
         | 
| 853 | 
            +
                    results.push(shiftedEvent1.asTS().difference(shiftedEvent2.asTS(), 'min'))
         | 
| 854 | 
            +
              results
         | 
| 855 | 
            +
            @TIMEDIFF = TIMEDIFF
         | 
| 823 856 |  | 
| 824 857 | 
             
            @OidDictionary = {};
         | 
| 825 858 |  | 
| @@ -1,7 +1,11 @@ | |
| 1 1 | 
             
            class @Logger
         | 
| 2 2 | 
             
              @logger: []
         | 
| 3 | 
            +
              @rationale: {}
         | 
| 3 4 | 
             
              @info: (string) ->
         | 
| 4 5 | 
             
                @logger.push("#{Logger.indent()}#{string}")
         | 
| 6 | 
            +
              @record: (id, result) ->
         | 
| 7 | 
            +
                if result? and typeof(result.isTrue) == 'function'
         | 
| 8 | 
            +
                  @rationale[id] = result.isTrue()
         | 
| 5 9 | 
             
              @enabled: true
         | 
| 6 10 | 
             
              @initialized: false
         | 
| 7 11 | 
             
              @indentCount = 0
         | 
| @@ -40,12 +44,17 @@ class @Logger | |
| 40 44 |  | 
| 41 45 | 
             
            @enableMeasureLogging = (hqmfjs) ->
         | 
| 42 46 | 
             
              _.each(_.functions(hqmfjs), (method) ->
         | 
| 43 | 
            -
                hqmfjs[method] = _.wrap(hqmfjs[method], (func | 
| 47 | 
            +
                hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  args = Array.prototype.slice.call(arguments,1)
         | 
| 50 | 
            +
             | 
| 44 51 | 
             
                  Logger.info("#{method}:")
         | 
| 45 52 | 
             
                  Logger.indentCount++
         | 
| 46 | 
            -
                  result = func( | 
| 53 | 
            +
                  result = func.apply(this, args)
         | 
| 54 | 
            +
             | 
| 47 55 | 
             
                  Logger.indentCount--
         | 
| 48 56 | 
             
                  Logger.info("#{method} -> #{Logger.asBoolean(result)}")
         | 
| 57 | 
            +
                  Logger.record(method,result)
         | 
| 49 58 | 
             
                  return result;
         | 
| 50 59 | 
             
                );
         | 
| 51 60 | 
             
              );
         | 
| @@ -73,12 +82,6 @@ class @Logger | |
| 73 82 | 
             
                );
         | 
| 74 83 |  | 
| 75 84 | 
             
                hQuery.CodedEntryList.prototype.match = _.wrap(hQuery.CodedEntryList.prototype.match, (func, codeSet, start, end) ->
         | 
| 76 | 
            -
                  
         | 
| 77 | 
            -
                  # if (codeSet)
         | 
| 78 | 
            -
                  #   Logger.info("matching: codeSets(#{_.keys(codeSet).join(",")}), #{start}, #{end}")
         | 
| 79 | 
            -
                  # else
         | 
| 80 | 
            -
                  #   Logger.info("matching: WARNING: CODE SETS ARE NULL, #{start}, #{end}")
         | 
| 81 | 
            -
                    
         | 
| 82 85 | 
             
                  func = _.bind(func, this, codeSet,start,end)
         | 
| 83 86 | 
             
                  result = func(codeSet,start,end)
         | 
| 84 87 | 
             
                  Logger.info("matched -> #{Logger.stringify(result)}")
         | 
| @@ -98,6 +101,7 @@ class @Logger | |
| 98 101 | 
             
                  result = func.apply(this, args)
         | 
| 99 102 | 
             
                  Logger.indentCount--
         | 
| 100 103 | 
             
                  Logger.info("atLeastOneTrue -> #{result}")
         | 
| 104 | 
            +
                  Logger.record("precondition_#{args[0]}",result)
         | 
| 101 105 | 
             
                  result
         | 
| 102 106 | 
             
                )
         | 
| 103 107 |  | 
| @@ -108,6 +112,7 @@ class @Logger | |
| 108 112 | 
             
                  result = func.apply(this, args)
         | 
| 109 113 | 
             
                  Logger.indentCount--
         | 
| 110 114 | 
             
                  Logger.info("allTrue -> #{result}")
         | 
| 115 | 
            +
                  Logger.record("precondition_#{args[0]}",result)
         | 
| 111 116 | 
             
                  result
         | 
| 112 117 | 
             
                )
         | 
| 113 118 |  | 
| @@ -118,6 +123,7 @@ class @Logger | |
| 118 123 | 
             
                  result = func.apply(this, args)
         | 
| 119 124 | 
             
                  Logger.indentCount--
         | 
| 120 125 | 
             
                  Logger.info("allFalse -> #{result}")
         | 
| 126 | 
            +
                  Logger.record("precondition_#{args[0]}",result)
         | 
| 121 127 | 
             
                  result
         | 
| 122 128 | 
             
                )
         | 
| 123 129 |  | 
| @@ -128,6 +134,7 @@ class @Logger | |
| 128 134 | 
             
                  result = func.apply(this, args)
         | 
| 129 135 | 
             
                  Logger.indentCount--
         | 
| 130 136 | 
             
                  Logger.info("atLeastOneFalse -> #{result}")
         | 
| 137 | 
            +
                  Logger.record("precondition_#{args[0]}",result)
         | 
| 131 138 | 
             
                  result
         | 
| 132 139 | 
             
                )
         | 
| 133 140 |  | 
| @@ -13,6 +13,10 @@ hQuery.CodedEntry::asIVL_TS = -> | |
| 13 13 | 
             
              tsHigh = new TS()
         | 
| 14 14 | 
             
              tsHigh.date = this.endDate() || this.date() || null
         | 
| 15 15 | 
             
              new IVL_TS(tsLow, tsHigh)
         | 
| 16 | 
            +
            hQuery.CodedEntry::asTS = ->
         | 
| 17 | 
            +
              ts = new TS()
         | 
| 18 | 
            +
              ts.date = this.timeStamp()
         | 
| 19 | 
            +
              ts
         | 
| 16 20 |  | 
| 17 21 | 
             
            hQuery.CodedEntry::respondTo = (functionName) ->
         | 
| 18 22 | 
             
              typeof(@[functionName]) == "function"
         | 
    
        data/hqmf2js.gemspec
    CHANGED
    
    | @@ -7,13 +7,15 @@ Gem::Specification.new do |s| | |
| 7 7 | 
             
              s.email = "hquery-talk@googlegroups.com"
         | 
| 8 8 | 
             
              s.homepage = "http://github.com/hquery/hqmf2js"
         | 
| 9 9 | 
             
              s.authors = ["Marc Hadley", "Andre Quina", "Andy Gregorowicz"]
         | 
| 10 | 
            -
              s.version = '1. | 
| 10 | 
            +
              s.version = '1.2.0'
         | 
| 11 11 |  | 
| 12 12 | 
             
              s.add_dependency 'nokogiri', '~> 1.5.5'
         | 
| 13 13 | 
             
              s.add_dependency 'tilt', '~> 1.3.3'
         | 
| 14 14 | 
             
              s.add_dependency 'coffee-script', '~> 2.2.0'
         | 
| 15 15 | 
             
              s.add_dependency 'sprockets', '~> 2.2.2'
         | 
| 16 16 | 
             
              s.add_development_dependency "awesome_print", "~> 1.1.0"
         | 
| 17 | 
            +
              s.add_dependency 'health-data-standards', '~> 3.0.1'
         | 
| 18 | 
            +
              s.add_dependency 'hquery-patient-api', '~> 1.0.1'
         | 
| 17 19 |  | 
| 18 20 | 
             
              s.files = s.files = `git ls-files`.split("\n")
         | 
| 19 21 | 
             
            end
         | 
| @@ -16,9 +16,9 @@ module HQMF2JS | |
| 16 16 | 
             
                    translation = {}
         | 
| 17 17 | 
             
                    value_sets.each do |value_set|
         | 
| 18 18 | 
             
                      code_sets = {}
         | 
| 19 | 
            -
                      value_set[" | 
| 20 | 
            -
                        code_sets[code_set[" | 
| 21 | 
            -
                        code_sets[code_set[" | 
| 19 | 
            +
                      value_set["concepts"].each do |code_set|
         | 
| 20 | 
            +
                        code_sets[code_set["code_system_name"]] ||= []
         | 
| 21 | 
            +
                        code_sets[code_set["code_system_name"]].concat(code_set["code"].to_a)
         | 
| 22 22 | 
             
                      end
         | 
| 23 23 |  | 
| 24 24 | 
             
                      translation[value_set["oid"]] = code_sets
         | 
| @@ -35,6 +35,7 @@ module HQMF2JS | |
| 35 35 | 
             
                  #   <ValueSet id="2.16.840.1.113883.3.464.1.14" displayName="birth date">
         | 
| 36 36 | 
             
                  #     <ConceptList xml:lang="en-US">
         | 
| 37 37 | 
             
                  #       <Concept code="00110" codeSystemName="HL7" displayName="Date/Time of birth (TS)"
         | 
| 38 | 
            +
                  
         | 
| 38 39 | 
             
                  #         codeSystemVersion="3"/>
         | 
| 39 40 | 
             
                  #      </ConceptList>
         | 
| 40 41 | 
             
                  #   </ValueSet>
         | 
| @@ -78,4 +79,4 @@ module HQMF2JS | |
| 78 79 |  | 
| 79 80 | 
             
                end
         | 
| 80 81 | 
             
              end
         | 
| 81 | 
            -
            end
         | 
| 82 | 
            +
            end
         | 
| @@ -6,7 +6,7 @@ var <%=  js_name(criteria) %> = <%= js_for_value(criteria.value) %>; | |
| 6 6 |  | 
| 7 7 | 
             
            // Data critera
         | 
| 8 8 | 
             
            <%- all_criteria.select {|c| c.type != :variable}.each do |criteria| -%>
         | 
| 9 | 
            -
            hqmfjs.<%= js_name(criteria) %> = function(patient) {
         | 
| 9 | 
            +
            hqmfjs.<%= js_name(criteria) %> = function(patient, initialSpecificContext) {
         | 
| 10 10 | 
             
              <%- if criteria.type == :characteristic and !criteria.property.nil? -%>
         | 
| 11 11 | 
             
            <%= js_for_characteristic(criteria) %>
         | 
| 12 12 | 
             
              <%- else -%>
         | 
| @@ -37,7 +37,7 @@ hqmfjs.<%= js_name(criteria) %> = function(patient) { | |
| 37 37 | 
             
                <%- end -%>
         | 
| 38 38 | 
             
                <%- if criteria.subset_operators -%>
         | 
| 39 39 | 
             
                  <%- criteria.subset_operators.select {|subset_operator| subset_operator.type}.each do |subset_operator| -%>
         | 
| 40 | 
            -
              events = <%= subset_operator.type %>(events<%= ", #{js_for_bounds(subset_operator.value)}" if subset_operator.value  | 
| 40 | 
            +
              events = <%= subset_operator.type %>(events<%= ", #{js_for_bounds(subset_operator.value)}" if subset_operator.value %>, initialSpecificContext);
         | 
| 41 41 | 
             
                  <%- end # each operator -%>
         | 
| 42 42 | 
             
                <%- end # subset operators -%>
         | 
| 43 43 | 
             
              return events;
         | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
              var events = <%= criteria.derivation_operator %>(
         | 
| 2 2 | 
             
                <%- criteria.children_criteria.each_with_index do |child, index| -%>
         | 
| 3 | 
            -
                <%= "hqmfjs.#{child}(patient)" %><%= "," if index<criteria.children_criteria.length-1 %>
         | 
| 3 | 
            +
                <%= "hqmfjs.#{child}(patient, initialSpecificContext)" %><%= "," if index<criteria.children_criteria.length-1 %>
         | 
| 4 4 | 
             
                <%- end -%>
         | 
| 5 5 | 
             
              );
         | 
    
        data/lib/generator/js.rb
    CHANGED
    
    | @@ -138,8 +138,8 @@ module HQMF2JS | |
| 138 138 | 
             
                  end
         | 
| 139 139 |  | 
| 140 140 | 
             
                  # Returns the JavaScript generated for a HQMF::Precondition
         | 
| 141 | 
            -
                  def js_for_precondition(precondition, indent)
         | 
| 142 | 
            -
                    HQMF2JS::Generator.render_template('precondition', {'doc' => doc, 'precondition' => precondition, 'indent' => indent})
         | 
| 141 | 
            +
                  def js_for_precondition(precondition, indent, context=false)
         | 
| 142 | 
            +
                    HQMF2JS::Generator.render_template('precondition', {'doc' => doc, 'precondition' => precondition, 'indent' => indent, 'context' => context})
         | 
| 143 143 | 
             
                  end
         | 
| 144 144 |  | 
| 145 145 | 
             
                  def patient_api_method(criteria)
         | 
| @@ -202,6 +202,7 @@ module HQMF2JS | |
| 202 202 | 
             
                    #{js_for(population[HQMF::PopulationCriteria::DENEXCEP], HQMF::PopulationCriteria::DENEXCEP)}
         | 
| 203 203 | 
             
                    // CV
         | 
| 204 204 | 
             
                    #{js_for(population[HQMF::PopulationCriteria::MSRPOPL], HQMF::PopulationCriteria::MSRPOPL)}
         | 
| 205 | 
            +
                    #{js_for(population[HQMF::PopulationCriteria::OBSERV], HQMF::PopulationCriteria::OBSERV)}
         | 
| 205 206 | 
             
                    "
         | 
| 206 207 | 
             
                  end
         | 
| 207 208 |  | 
| @@ -224,7 +225,11 @@ module HQMF2JS | |
| 224 225 | 
             
                    type ||= criteria_code
         | 
| 225 226 | 
             
                    criteria = @doc.population_criteria(criteria_code)
         | 
| 226 227 | 
             
                    if criteria && criteria.preconditions && criteria.preconditions.length > 0
         | 
| 227 | 
            -
                       | 
| 228 | 
            +
                      if type==HQMF::PopulationCriteria::OBSERV
         | 
| 229 | 
            +
                        HQMF2JS::Generator.render_template('observation_criteria', {'doc' => @doc, 'criteria' => criteria, 'type'=>type})
         | 
| 230 | 
            +
                      else
         | 
| 231 | 
            +
                        HQMF2JS::Generator.render_template('population_criteria', {'doc' => @doc, 'criteria' => criteria, 'type'=>type})
         | 
| 232 | 
            +
                      end
         | 
| 228 233 | 
             
                    else
         | 
| 229 234 | 
             
                      "hqmfjs.#{type} = function(patient) { return new Boolean(#{when_not_found}); }"
         | 
| 230 235 | 
             
                    end
         | 
| @@ -13,6 +13,7 @@ hqmfjs.MeasurePeriod = function(patient) { | |
| 13 13 | 
             
            }
         | 
| 14 14 | 
             
            if (typeof effective_date === 'number') {
         | 
| 15 15 | 
             
              MeasurePeriod.high.date = new Date(1000*effective_date);
         | 
| 16 | 
            -
               | 
| 16 | 
            +
              // add one minute before pulling off the year.  This turns 12-31-2012 23:59 into 1-1-2013 00:00 => 1-1-2012 00:00
         | 
| 17 | 
            +
              MeasurePeriod.low.date = new Date(1000*(effective_date+60));
         | 
| 17 18 | 
             
              MeasurePeriod.low.date.setFullYear(MeasurePeriod.low.date.getFullYear()-1);
         | 
| 18 19 | 
             
            }
         | 
| @@ -1,14 +1,16 @@ | |
| 1 1 | 
             
            <%- if precondition.conjunction? -%>
         | 
| 2 2 | 
             
            <%- if indent>0 -%>
         | 
| 3 | 
            -
            <%= "\n#{'  '*(indent+1)}#{conjunction_code_for(precondition)}(" -%>
         | 
| 3 | 
            +
            <%= "\n#{'  '*(indent+1)}#{conjunction_code_for(precondition)}('#{precondition.id}'," -%>
         | 
| 4 4 | 
             
            <%- else -%>
         | 
| 5 | 
            -
            <%= "#{conjunction_code_for(precondition)}(" -%>
         | 
| 5 | 
            +
            <%= "#{conjunction_code_for(precondition)}('#{precondition.id}'," -%>
         | 
| 6 6 | 
             
            <%- end -%>
         | 
| 7 7 | 
             
            <%- precondition.preconditions.each_with_index do |child, index| -%>
         | 
| 8 | 
            -
            <%= "#{'  '*(indent+1)}#{js_for_precondition(child, indent+1)}" -%>
         | 
| 8 | 
            +
            <%= "#{'  '*(indent+1)}#{js_for_precondition(child, indent+1, context)}" -%>
         | 
| 9 9 | 
             
            <%= "," if index < precondition.preconditions.length-1 -%>
         | 
| 10 10 | 
             
            <%- end -%>
         | 
| 11 11 | 
             
            <%= "\n#{'  '*(indent+1)})" -%>
         | 
| 12 | 
            +
            <%- elsif context -%>
         | 
| 13 | 
            +
            <%= " hqmfjs.#{js_name(precondition.reference)}(patient, initialSpecificContext)" -%>
         | 
| 12 14 | 
             
            <%- else -%>
         | 
| 13 15 | 
             
            <%= "\n#{'  '*(indent+1)}hqmfjs.#{js_name(precondition.reference)}(patient)" -%>
         | 
| 14 16 | 
             
            <%- end -%>
         | 
    
        data/lib/tasks/convert.rake
    CHANGED
    
    | @@ -29,15 +29,19 @@ namespace :hqmf do | |
| 29 29 | 
             
                  f.write("// #########################\n\n")
         | 
| 30 30 |  | 
| 31 31 | 
             
                  f.write("// INITIAL PATIENT POPULATION\n")
         | 
| 32 | 
            -
                  f.write(gen.js_for( | 
| 33 | 
            -
                  f.write("// DENOMINATOR\n")
         | 
| 34 | 
            -
                  f.write(gen.js_for( | 
| 35 | 
            -
                  f.write("// NUMERATOR\n")
         | 
| 36 | 
            -
                  f.write(gen.js_for( | 
| 37 | 
            -
                  f.write("// EXCLUSIONS\n")
         | 
| 38 | 
            -
                  f.write(gen.js_for( | 
| 39 | 
            -
                  f.write("// DENOMINATOR EXCEPTIONS\n")
         | 
| 40 | 
            -
                  f.write(gen.js_for( | 
| 32 | 
            +
                  f.write(gen.js_for(HQMF::PopulationCriteria::IPP))
         | 
| 33 | 
            +
                  f.write("\n// DENOMINATOR\n")
         | 
| 34 | 
            +
                  f.write(gen.js_for(HQMF::PopulationCriteria::DENOM))
         | 
| 35 | 
            +
                  f.write("\n// NUMERATOR\n")
         | 
| 36 | 
            +
                  f.write(gen.js_for(HQMF::PopulationCriteria::NUMER))
         | 
| 37 | 
            +
                  f.write("\n// EXCLUSIONS\n")
         | 
| 38 | 
            +
                  f.write(gen.js_for(HQMF::PopulationCriteria::DENEX))
         | 
| 39 | 
            +
                  f.write("\n// DENOMINATOR EXCEPTIONS\n")
         | 
| 40 | 
            +
                  f.write(gen.js_for(HQMF::PopulationCriteria::DENEXCEP))
         | 
| 41 | 
            +
                  f.write("\n// MSRPOPL\n")
         | 
| 42 | 
            +
                  f.write(gen.js_for(HQMF::PopulationCriteria::MSRPOPL))
         | 
| 43 | 
            +
                  f.write("\n// OBSERV\n")
         | 
| 44 | 
            +
                  f.write(gen.js_for(HQMF::PopulationCriteria::OBSERV))
         | 
| 41 45 | 
             
                end
         | 
| 42 46 |  | 
| 43 47 | 
             
                puts "wrote javascript to: #{out_file}"
         | 
| @@ -893,7 +893,7 @@ | |
| 893 893 | 
             
                            {
         | 
| 894 894 | 
             
                                "type": "SUMMARY",
         | 
| 895 895 | 
             
                                "value": {
         | 
| 896 | 
            -
                                    "type": " | 
| 896 | 
            +
                                    "type": "IVL_PQ",
         | 
| 897 897 | 
             
                                    "low": {
         | 
| 898 898 | 
             
                                        "type": "PQ",
         | 
| 899 899 | 
             
                                        "value": "2",
         | 
| @@ -1118,7 +1118,7 @@ | |
| 1118 1118 | 
             
                            {
         | 
| 1119 1119 | 
             
                                "type": "COUNT",
         | 
| 1120 1120 | 
             
                                "value": {
         | 
| 1121 | 
            -
                                    "type": " | 
| 1121 | 
            +
                                    "type": "IVL_PQ",
         | 
| 1122 1122 | 
             
                                    "low": {
         | 
| 1123 1123 | 
             
                                        "type": "PQ",
         | 
| 1124 1124 | 
             
                                        "value": "3",
         | 
| @@ -1145,7 +1145,7 @@ | |
| 1145 1145 | 
             
                            {
         | 
| 1146 1146 | 
             
                                "type": "COUNT",
         | 
| 1147 1147 | 
             
                                "value": {
         | 
| 1148 | 
            -
                                    "type": " | 
| 1148 | 
            +
                                    "type": "IVL_PQ",
         | 
| 1149 1149 | 
             
                                    "low": {
         | 
| 1150 1150 | 
             
                                        "type": "PQ",
         | 
| 1151 1151 | 
             
                                        "value": "5",
         | 
| @@ -34,6 +34,42 @@ class CustomCalculationsTest < Test::Unit::TestCase | |
| 34 34 | 
             
                  inr_b9 = new hQuery.CodedEntry({time:#{Time.gm(2010,10,31).to_i}, values:[{scalar:'1.8'}]})
         | 
| 35 35 |  | 
| 36 36 | 
             
                  list2 = new hqmf.CustomCalc.PercentTTREntries([inr_b1,inr_b2,inr_b3,inr_b4,inr_b5,inr_b6,inr_b7,inr_b8,inr_b9])
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  inr_c1 = new hQuery.CodedEntry({time:#{Time.gm(2010,1,5).to_i}, values:[{scalar:'2.8'}]})
         | 
| 39 | 
            +
                  inr_c2 = new hQuery.CodedEntry({time:#{Time.gm(2010,1,18).to_i}, values:[{scalar:'3.5'}]})
         | 
| 40 | 
            +
                  inr_c3 = new hQuery.CodedEntry({time:#{Time.gm(2010,2,2).to_i}, values:[{scalar:'3.4'}]})
         | 
| 41 | 
            +
                  inr_c4 = new hQuery.CodedEntry({time:#{Time.gm(2010,2,15).to_i}, values:[{scalar:'3.9'}]})
         | 
| 42 | 
            +
                  inr_c5 = new hQuery.CodedEntry({time:#{Time.gm(2010,3,10).to_i}, values:[{scalar:'1.7'}]})
         | 
| 43 | 
            +
                  inr_c6 = new hQuery.CodedEntry({time:#{Time.gm(2010,3,24).to_i}, values:[{scalar:'2.3'}]})
         | 
| 44 | 
            +
                  inr_c7 = new hQuery.CodedEntry({time:#{Time.gm(2010,4,12).to_i}, values:[{scalar:'2.4'}]})
         | 
| 45 | 
            +
                  inr_c8 = new hQuery.CodedEntry({time:#{Time.gm(2010,5,13).to_i}, values:[{scalar:'3.2'}]})
         | 
| 46 | 
            +
                  inr_c9 = new hQuery.CodedEntry({time:#{Time.gm(2010,5,27).to_i}, values:[{scalar:'3.5'}]})
         | 
| 47 | 
            +
                  inr_c10 = new hQuery.CodedEntry({time:#{Time.gm(2010,6,10).to_i}, values:[{scalar:'3.5'}]})
         | 
| 48 | 
            +
                  inr_c11 = new hQuery.CodedEntry({time:#{Time.gm(2010,6,24).to_i}, values:[{scalar:'3.4'}]})
         | 
| 49 | 
            +
                  inr_c12 = new hQuery.CodedEntry({time:#{Time.gm(2010,7,8).to_i}, values:[{scalar:'2.1'}]})
         | 
| 50 | 
            +
                  inr_c13 = new hQuery.CodedEntry({time:#{Time.gm(2010,7,22).to_i}, values:[{scalar:'2.6'}]})
         | 
| 51 | 
            +
                  
         | 
| 52 | 
            +
                  list3 = new hqmf.CustomCalc.PercentTTREntries([inr_c10,inr_c2,inr_c6,inr_c9,inr_c5,inr_c3,inr_c7,inr_c8,inr_c4,inr_c1,inr_c11,inr_c12,inr_c13])
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  inr_c1 = new hQuery.CodedEntry({time:#{Time.gm(2010,1,5).to_i}, values:[{scalar:'2.8'}]})
         | 
| 55 | 
            +
                  inr_c2 = new hQuery.CodedEntry({time:#{Time.gm(2010,1,18).to_i}, values:[{scalar:'3.5'}]})
         | 
| 56 | 
            +
                  inr_c3 = new hQuery.CodedEntry({time:#{Time.gm(2010,2,2).to_i}, values:[{scalar:'3.4'}]})
         | 
| 57 | 
            +
                  inr_c4 = new hQuery.CodedEntry({time:#{Time.gm(2010,2,2).to_i}, values:[{scalar:'2.1'}]})
         | 
| 58 | 
            +
                  inr_c5 = new hQuery.CodedEntry({time:#{Time.gm(2010,2,15).to_i}, values:[{scalar:'3.9'}]})
         | 
| 59 | 
            +
                  inr_c6 = new hQuery.CodedEntry({time:#{Time.gm(2010,3,10).to_i}, values:[{scalar:'1.7'}]})
         | 
| 60 | 
            +
                  inr_c7 = new hQuery.CodedEntry({time:#{Time.gm(2010,3,11).to_i}, values:[{scalar:'0.7'}]})
         | 
| 61 | 
            +
                  inr_c8 = new hQuery.CodedEntry({time:#{Time.gm(2010,3,24).to_i}, values:[{scalar:'2.9'},{scalar:'2.3'}]})
         | 
| 62 | 
            +
                  inr_c9 = new hQuery.CodedEntry({time:#{Time.gm(2010,4,12).to_i}, values:[{scalar:'2.4'}]})
         | 
| 63 | 
            +
                  inr_c10 = new hQuery.CodedEntry({time:#{Time.gm(2010,5,13).to_i}, values:[{scalar:'3.2'}]})
         | 
| 64 | 
            +
                  inr_c11 = new hQuery.CodedEntry({time:#{Time.gm(2010,5,13).to_i}, values:[{scalar:'3.6'}]})
         | 
| 65 | 
            +
                  inr_c12 = new hQuery.CodedEntry({time:#{Time.gm(2010,5,27).to_i}, values:[{scalar:'13.5'}]})
         | 
| 66 | 
            +
                  inr_c13 = new hQuery.CodedEntry({time:#{Time.gm(2010,6,10).to_i}, values:[{scalar:'3.5'}]})
         | 
| 67 | 
            +
                  inr_c14 = new hQuery.CodedEntry({time:#{Time.gm(2010,6,24).to_i}, values:[{scalar:'3.4'}]})
         | 
| 68 | 
            +
                  inr_c15 = new hQuery.CodedEntry({time:#{Time.gm(2010,7,8).to_i}, values:[{scalar:'12.1'}]})
         | 
| 69 | 
            +
                  inr_c16 = new hQuery.CodedEntry({time:#{Time.gm(2010,7,22).to_i}, values:[{scalar:'2.6'}, {scalar:'2.1'}]})
         | 
| 70 | 
            +
                  
         | 
| 71 | 
            +
                  list4 = new hqmf.CustomCalc.PercentTTREntries([inr_c9,inr_c8,inr_c3,inr_c14,inr_c10,inr_c6,inr_c7,inr_c2,inr_c1,inr_c5,inr_c11,inr_c12,inr_c13,inr_c4,inr_c15,inr_c16])
         | 
| 72 | 
            +
             | 
| 37 73 | 
             
                "
         | 
| 38 74 | 
             
                @context.eval(test_initialize_js)
         | 
| 39 75 |  | 
| @@ -69,6 +105,36 @@ class CustomCalculationsTest < Test::Unit::TestCase | |
| 69 105 | 
             
              def test_calculate_percent_ttr
         | 
| 70 106 | 
             
                assert @context.eval("Math.abs(list.calculatePercentTTR() - 43.99552468) < .001")
         | 
| 71 107 | 
             
              end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
              def test_calculate_ttr_testdeck_record
         | 
| 110 | 
            +
                assert @context.eval("Math.abs(list2.calculateTTR() - 203.66666666) < .001")
         | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
              def test_calculate_percent_ttr_testdeck_record
         | 
| 114 | 
            +
                assert @context.eval("Math.abs(list2.calculatePercentTTR() - 95.6181533646322) < .001")
         | 
| 115 | 
            +
              end
         | 
| 72 116 |  | 
| 117 | 
            +
              def test_calculate_ttr_out_of_order
         | 
| 118 | 
            +
                assert @context.eval("Math.abs(list3.calculateTTR() - 87.11113886) < .001")
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              def test_calculate_percent_ttr_out_of_order
         | 
| 122 | 
            +
                assert @context.eval("Math.abs(list3.calculatePercentTTR() - 43.99552468) < .001")
         | 
| 123 | 
            +
              end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
              def test_cleanup_of_inr_values
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                cleaned_inrs = [2.8, 3.5, 2.1, 3.9, 1.7, 2.3, 2.4, 3.2, 10.0, 3.5, 3.4, 10.0, 2.6]
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                assert @context.eval("list4.length == #{cleaned_inrs.size}")
         | 
| 130 | 
            +
                cleaned_inrs.each_with_index do |inr,index|
         | 
| 131 | 
            +
                  assert @context.eval("list4[#{index}].values()[0].scalar() == #{inr}")
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                assert @context.eval("Math.abs(list4.calculateTTR() - 80.3184450684) < .001")
         | 
| 135 | 
            +
                assert @context.eval("Math.abs(list4.calculatePercentTTR() - 40.56487124668) < .001")
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
             | 
| 73 139 |  | 
| 74 140 | 
             
            end
         | 
| @@ -17,31 +17,31 @@ class LibraryFunctionTest < Test::Unit::TestCase | |
| 17 17 | 
             
              end
         | 
| 18 18 |  | 
| 19 19 | 
             
              def test_all_true
         | 
| 20 | 
            -
                @context.eval('allTrue(new Boolean(false),new Boolean(false),new Boolean(false)).isTrue()').must_equal false
         | 
| 21 | 
            -
                @context.eval('allTrue(new Boolean(false),new Boolean(true),new Boolean(false)).isTrue()').must_equal false
         | 
| 22 | 
            -
                @context.eval('allTrue(new Boolean(true),new Boolean(true),new Boolean(true)).isTrue()').must_equal true
         | 
| 23 | 
            -
                @context.eval('allTrue().isTrue()').must_equal false
         | 
| 20 | 
            +
                @context.eval('allTrue(1,new Boolean(false),new Boolean(false),new Boolean(false)).isTrue()').must_equal false
         | 
| 21 | 
            +
                @context.eval('allTrue(1,new Boolean(false),new Boolean(true),new Boolean(false)).isTrue()').must_equal false
         | 
| 22 | 
            +
                @context.eval('allTrue(1,new Boolean(true),new Boolean(true),new Boolean(true)).isTrue()').must_equal true
         | 
| 23 | 
            +
                @context.eval('allTrue(1).isTrue()').must_equal false
         | 
| 24 24 | 
             
              end
         | 
| 25 25 |  | 
| 26 26 | 
             
              def test_at_least_one_true
         | 
| 27 | 
            -
                @context.eval('atLeastOneTrue(new Boolean(true),new Boolean(false),new Boolean(false)).isTrue()').must_equal true
         | 
| 28 | 
            -
                @context.eval('atLeastOneTrue(new Boolean(true),new Boolean(true),new Boolean(true)).isTrue()').must_equal true
         | 
| 29 | 
            -
                @context.eval('atLeastOneTrue(new Boolean(false),new Boolean(false),new Boolean(false)).isTrue()').must_equal false
         | 
| 30 | 
            -
                @context.eval('atLeastOneTrue().isTrue()').must_equal false
         | 
| 27 | 
            +
                @context.eval('atLeastOneTrue(1,new Boolean(true),new Boolean(false),new Boolean(false)).isTrue()').must_equal true
         | 
| 28 | 
            +
                @context.eval('atLeastOneTrue(1,new Boolean(true),new Boolean(true),new Boolean(true)).isTrue()').must_equal true
         | 
| 29 | 
            +
                @context.eval('atLeastOneTrue(1,new Boolean(false),new Boolean(false),new Boolean(false)).isTrue()').must_equal false
         | 
| 30 | 
            +
                @context.eval('atLeastOneTrue(1).isTrue()').must_equal false
         | 
| 31 31 | 
             
              end
         | 
| 32 32 |  | 
| 33 33 | 
             
              def test_all_false
         | 
| 34 | 
            -
                @context.eval('allFalse(new Boolean(false),new Boolean(false),new Boolean(false)).isTrue()').must_equal true
         | 
| 35 | 
            -
                @context.eval('allFalse(new Boolean(false),new Boolean(true),new Boolean(false)).isTrue()').must_equal false
         | 
| 36 | 
            -
                @context.eval('allFalse(new Boolean(true),new Boolean(true),new Boolean(true)).isTrue()').must_equal false
         | 
| 37 | 
            -
                @context.eval('allFalse().isTrue()').must_equal false
         | 
| 34 | 
            +
                @context.eval('allFalse(1,new Boolean(false),new Boolean(false),new Boolean(false)).isTrue()').must_equal true
         | 
| 35 | 
            +
                @context.eval('allFalse(1,new Boolean(false),new Boolean(true),new Boolean(false)).isTrue()').must_equal false
         | 
| 36 | 
            +
                @context.eval('allFalse(1,new Boolean(true),new Boolean(true),new Boolean(true)).isTrue()').must_equal false
         | 
| 37 | 
            +
                @context.eval('allFalse(1).isTrue()').must_equal false
         | 
| 38 38 | 
             
              end
         | 
| 39 39 |  | 
| 40 40 | 
             
              def test_at_least_one_false
         | 
| 41 | 
            -
                @context.eval('atLeastOneFalse(new Boolean(true),new Boolean(false),new Boolean(false)).isTrue()').must_equal true
         | 
| 42 | 
            -
                @context.eval('atLeastOneFalse(new Boolean(true),new Boolean(true),new Boolean(true)).isTrue()').must_equal false
         | 
| 43 | 
            -
                @context.eval('atLeastOneFalse(new Boolean(false),new Boolean(false),new Boolean(false)).isTrue()').must_equal true
         | 
| 44 | 
            -
                @context.eval('atLeastOneFalse().isTrue()').must_equal false
         | 
| 41 | 
            +
                @context.eval('atLeastOneFalse(1,new Boolean(true),new Boolean(false),new Boolean(false)).isTrue()').must_equal true
         | 
| 42 | 
            +
                @context.eval('atLeastOneFalse(1,new Boolean(true),new Boolean(true),new Boolean(true)).isTrue()').must_equal false
         | 
| 43 | 
            +
                @context.eval('atLeastOneFalse(1,new Boolean(false),new Boolean(false),new Boolean(false)).isTrue()').must_equal true
         | 
| 44 | 
            +
                @context.eval('atLeastOneFalse(1).isTrue()').must_equal false
         | 
| 45 45 | 
             
              end
         | 
| 46 46 |  | 
| 47 47 | 
             
              def test_patient_extensions
         | 
    
        data/test/unit/specifics_test.rb
    CHANGED
    
    | @@ -202,6 +202,29 @@ class SpecificsTest < Test::Unit::TestCase | |
| 202 202 |  | 
| 203 203 | 
             
              end
         | 
| 204 204 |  | 
| 205 | 
            +
              def test_specifics_timediff
         | 
| 206 | 
            +
                init_rows = "
         | 
| 207 | 
            +
                  var row1 = new Row('OccurrenceAEncounter',{'OccurrenceAEncounter':{'id':1},'OccurrenceBEncounter':{'id':20}});
         | 
| 208 | 
            +
                  var row2 = new Row('OccurrenceAEncounter',{'OccurrenceAEncounter':{'id':2},'OccurrenceBEncounter':{'id':20}});
         | 
| 209 | 
            +
                  var row3 = new Row('OccurrenceAEncounter',{'OccurrenceAEncounter':{'id':3},'OccurrenceBEncounter':{'id':30}});
         | 
| 210 | 
            +
                  
         | 
| 211 | 
            +
                  var specific = new hqmf.SpecificOccurrence([row1,row2,row3]);
         | 
| 212 | 
            +
                  
         | 
| 213 | 
            +
                  var ts1 = new TS('20100101100000');
         | 
| 214 | 
            +
                  var ts2 = new TS('20100101101000');
         | 
| 215 | 
            +
                  
         | 
| 216 | 
            +
                  var events1 = [{'id': 1, 'asTS': function() {return ts1;}}];
         | 
| 217 | 
            +
                  events1.specific_occurrence = 'OccurrenceAEncounter';
         | 
| 218 | 
            +
                  var events2 = [{'id': 20, 'asTS': function() {return ts2;}},{'id': 30, 'asTS': function() {return ts2;}}];
         | 
| 219 | 
            +
                  events2.specific_occurrence = 'OccurrenceBEncounter';
         | 
| 220 | 
            +
                  var timediffs = TIMEDIFF(XPRODUCT(events1, events2), null, specific);
         | 
| 221 | 
            +
                "
         | 
| 222 | 
            +
                
         | 
| 223 | 
            +
                @context.eval(init_rows)
         | 
| 224 | 
            +
                @context.eval("timediffs.length").must_equal 1
         | 
| 225 | 
            +
                @context.eval("timediffs[0]").must_equal 10
         | 
| 226 | 
            +
              end
         | 
| 227 | 
            +
              
         | 
| 205 228 | 
             
              def test_specifics_event_counting
         | 
| 206 229 |  | 
| 207 230 | 
             
                init_rows = "
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: hqmf2js
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.2.0
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -11,7 +11,7 @@ authors: | |
| 11 11 | 
             
            autorequire: 
         | 
| 12 12 | 
             
            bindir: bin
         | 
| 13 13 | 
             
            cert_chain: []
         | 
| 14 | 
            -
            date:  | 
| 14 | 
            +
            date: 2013-02-27 00:00:00.000000000 Z
         | 
| 15 15 | 
             
            dependencies:
         | 
| 16 16 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 17 17 | 
             
              name: nokogiri
         | 
| @@ -93,6 +93,38 @@ dependencies: | |
| 93 93 | 
             
                - - ~>
         | 
| 94 94 | 
             
                  - !ruby/object:Gem::Version
         | 
| 95 95 | 
             
                    version: 1.1.0
         | 
| 96 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 97 | 
            +
              name: health-data-standards
         | 
| 98 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 99 | 
            +
                none: false
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - ~>
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: 3.0.1
         | 
| 104 | 
            +
              type: :runtime
         | 
| 105 | 
            +
              prerelease: false
         | 
| 106 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
                none: false
         | 
| 108 | 
            +
                requirements:
         | 
| 109 | 
            +
                - - ~>
         | 
| 110 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 111 | 
            +
                    version: 3.0.1
         | 
| 112 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 113 | 
            +
              name: hquery-patient-api
         | 
| 114 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 115 | 
            +
                none: false
         | 
| 116 | 
            +
                requirements:
         | 
| 117 | 
            +
                - - ~>
         | 
| 118 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 119 | 
            +
                    version: 1.0.1
         | 
| 120 | 
            +
              type: :runtime
         | 
| 121 | 
            +
              prerelease: false
         | 
| 122 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 123 | 
            +
                none: false
         | 
| 124 | 
            +
                requirements:
         | 
| 125 | 
            +
                - - ~>
         | 
| 126 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 127 | 
            +
                    version: 1.0.1
         | 
| 96 128 | 
             
            description: A library for converting HQMF files to executable JavaScript suitable
         | 
| 97 129 | 
             
              for use with the hQuery Gateway
         | 
| 98 130 | 
             
            email: hquery-talk@googlegroups.com
         | 
| @@ -124,6 +156,7 @@ files: | |
| 124 156 | 
             
            - lib/generator/derived_data.js.erb
         | 
| 125 157 | 
             
            - lib/generator/js.rb
         | 
| 126 158 | 
             
            - lib/generator/measure_period.js.erb
         | 
| 159 | 
            +
            - lib/generator/observation_criteria.js.erb
         | 
| 127 160 | 
             
            - lib/generator/patient_data.js.erb
         | 
| 128 161 | 
             
            - lib/generator/population_criteria.js.erb
         | 
| 129 162 | 
             
            - lib/generator/precondition.js.erb
         |