psc 0.0.1

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.
Files changed (47) hide show
  1. data/.gitignore +13 -0
  2. data/.rvmrc +2 -0
  3. data/.yardopts +4 -0
  4. data/CHANGELOG.md +4 -0
  5. data/Gemfile +20 -0
  6. data/LICENSE +20 -0
  7. data/README.md +163 -0
  8. data/Rakefile +69 -0
  9. data/cucumber.yml +13 -0
  10. data/features/step_definitions/eval_steps.rb +14 -0
  11. data/features/step_definitions/setup_steps.rb +7 -0
  12. data/features/studies.feature +21 -0
  13. data/features/support/env.rb +33 -0
  14. data/features/support/int_psc.rb +165 -0
  15. data/int-psc/README-int-psc.md +57 -0
  16. data/int-psc/hsqldb/baseline.log +197 -0
  17. data/int-psc/hsqldb/baseline.properties +17 -0
  18. data/int-psc/hsqldb/baseline.script +295 -0
  19. data/int-psc/hsqldb/datasource.properties +18 -0
  20. data/int-psc/hsqldb/datasource.script +2205 -0
  21. data/int-psc/jetty/jetty-runner-7.4.0.v20110414.jar +0 -0
  22. data/int-psc/state/ABC 1200.xml +115 -0
  23. data/int-psc/state/int-psc-state.xml +64 -0
  24. data/lib/psc.rb +47 -0
  25. data/lib/psc/client.rb +35 -0
  26. data/lib/psc/connection.rb +96 -0
  27. data/lib/psc/faraday.rb +11 -0
  28. data/lib/psc/faraday/http_basic.rb +35 -0
  29. data/lib/psc/faraday/psc_token.rb +42 -0
  30. data/lib/psc/faraday/string_is_xml.rb +25 -0
  31. data/lib/psc/version.rb +3 -0
  32. data/meta.rakefile +30 -0
  33. data/psc.gemspec +33 -0
  34. data/spec/fixtures/studies-json.http +37 -0
  35. data/spec/middleware_helper.rb +18 -0
  36. data/spec/psc/client_spec.rb +39 -0
  37. data/spec/psc/connection_spec.rb +156 -0
  38. data/spec/psc/faraday/http_basic_spec.rb +15 -0
  39. data/spec/psc/faraday/psc_token_spec.rb +38 -0
  40. data/spec/psc/faraday/string_is_xml_spec.rb +49 -0
  41. data/spec/psc/version_spec.rb +11 -0
  42. data/spec/psc_spec.rb +16 -0
  43. data/spec/spec_helper.rb +15 -0
  44. data/tasks/int-psc.rake +84 -0
  45. data/tasks/psc/TODO +3 -0
  46. data/tasks/psc/state.rb +393 -0
  47. metadata +311 -0
@@ -0,0 +1,115 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <study xmlns="http://bioinformatics.northwestern.edu/ns/psc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" assigned-identifier="ABC 1200" last-modified-date="2011-05-12T11:10:29.740Z" xsi:schemaLocation="http://bioinformatics.northwestern.edu/ns/psc http://bioinformatics.northwestern.edu/ns/psc/psc.xsd">
4
+ <planned-calendar id="9c9c8042-75f1-477a-8855-40e6084f0954"/>
5
+ <amendment name="[Original]" date="2011-05-12" mandatory="true" released-date="2011-05-12T11:10:29.740Z" updated-date="2011-05-12T10:44:34.568Z">
6
+ <planned-calendar-delta id="d7adaa30-e2f0-4415-a751-53ccee9433ca" node-id="9c9c8042-75f1-477a-8855-40e6084f0954">
7
+ <add id="234ae5fa-e712-473d-b395-7e5edf9ef532" index="0">
8
+ <epoch id="72e7e90a-5f09-49b7-9dc4-785d56cf4414" name="Treatment">
9
+ <study-segment id="f174f7c2-ceed-4c6c-8392-1688f34b7905" name="A">
10
+ <period id="e74bbe38-46ad-410c-acd8-fb70f9527c0b" name="Surgery" repetitions="1" start-day="1" duration-quantity="1" duration-unit="day">
11
+ <planned-activity id="db2ffa63-8c28-43cd-94c4-e8f6801ce42b" day="1">
12
+ <activity-reference code="1041" source="Northwestern University"/>
13
+ </planned-activity>
14
+ </period>
15
+ <period id="1d8227b3-8f40-424c-a238-bffcda982014" name="Frequent monitoring" repetitions="24" start-day="1" duration-quantity="1" duration-unit="week">
16
+ <planned-activity id="2da856a4-3d40-4d04-8804-c9ee2b9f90b3" day="1">
17
+ <activity-reference code="360" source="Northwestern University"/>
18
+ </planned-activity>
19
+ <planned-activity id="09791bfb-eaf6-418a-8516-fae296df23f0" day="1">
20
+ <activity-reference code="253" source="Northwestern University"/>
21
+ </planned-activity>
22
+ </period>
23
+ <period id="e93b9f37-43de-4873-a776-1e7fcefbec59" name="Infrequent monitoring" repetitions="6" start-day="1" duration-quantity="1" duration-unit="month">
24
+ <planned-activity id="3ad03935-5bdf-448e-88ee-ee656d12afe3" day="1">
25
+ <activity-reference code="701" source="Northwestern University"/>
26
+ </planned-activity>
27
+ <planned-activity id="6fdbfd73-6cc3-41a6-a388-b19cf2bf7b25" day="1">
28
+ <activity-reference code="451" source="Northwestern University"/>
29
+ </planned-activity>
30
+ </period>
31
+ <period id="0c7852e2-eca1-4b57-9e7a-2d222abf43ea" name="Intervention" repetitions="8" start-day="8" duration-quantity="3" duration-unit="week">
32
+ <planned-activity id="845b63f0-389d-4b7c-b9df-986b7dd3e4ad" day="1">
33
+ <activity-reference code="211" source="Northwestern University"/>
34
+ </planned-activity>
35
+ <planned-activity id="0be23936-1621-49b3-862e-90eee0b03bf4" day="15">
36
+ <activity-reference code="211" source="Northwestern University"/>
37
+ </planned-activity>
38
+ <planned-activity id="7f599ee3-f45f-4af1-bcfd-3d377b3bbc4a" day="8">
39
+ <activity-reference code="43" source="Northwestern University"/>
40
+ </planned-activity>
41
+ </period>
42
+ </study-segment>
43
+ <study-segment id="fe329f59-1253-405a-9933-ea2d70bdf0dc" name="B">
44
+ <period id="538baa4e-6e4f-4e67-a112-b5a5d1200ba9" name="Frequent monitoring" repetitions="24" start-day="1" duration-quantity="1" duration-unit="week">
45
+ <planned-activity id="e742696d-c066-4e59-9bd2-f064a468ca87" day="1">
46
+ <activity-reference code="360" source="Northwestern University"/>
47
+ </planned-activity>
48
+ <planned-activity id="d882f175-13ae-4c16-9aa2-38f27c2ea2a6" day="1">
49
+ <activity-reference code="253" source="Northwestern University"/>
50
+ </planned-activity>
51
+ </period>
52
+ <period id="d54584c4-acc5-4de9-8323-ed36cbced4bc" name="Infrequent monitoring" repetitions="6" start-day="1" duration-quantity="1" duration-unit="month">
53
+ <planned-activity id="b23569f5-1268-4264-8c4d-bae166616d16" day="1">
54
+ <activity-reference code="701" source="Northwestern University"/>
55
+ </planned-activity>
56
+ <planned-activity id="3c54d7b4-f2ec-4b9e-9fe4-b6d13b92aeba" day="1">
57
+ <activity-reference code="451" source="Northwestern University"/>
58
+ </planned-activity>
59
+ </period>
60
+ <period id="b85661ef-ff19-462f-83a4-3e53ed69cd84" name="Intervention" repetitions="8" start-day="8" duration-quantity="3" duration-unit="week">
61
+ <planned-activity id="23a0aac4-87f6-4cd3-8df1-71bee82505ae" day="1">
62
+ <activity-reference code="211" source="Northwestern University"/>
63
+ </planned-activity>
64
+ <planned-activity id="24deeecc-cba8-4d8c-bc55-35048970bb8e" day="15">
65
+ <activity-reference code="211" source="Northwestern University"/>
66
+ </planned-activity>
67
+ <planned-activity id="40cce9be-3a32-4477-9c8d-79104b8625f0" day="8">
68
+ <activity-reference code="43" source="Northwestern University"/>
69
+ </planned-activity>
70
+ </period>
71
+ </study-segment>
72
+ </epoch>
73
+ </add>
74
+ <add id="1b02eb68-d1c8-4d11-88f2-4785ff91f0bb" index="1">
75
+ <epoch id="1d0d08cc-ed40-4ebb-923f-ebe0c29e814d" name="Follow up">
76
+ <study-segment id="4c01e031-1fe9-41ad-970c-368cb57c0c8e" name="Follow up">
77
+ <period id="3b8bff21-4d30-475f-a9b7-a39afed63b94" name="QoL" repetitions="18" start-day="1" duration-quantity="1" duration-unit="quarter">
78
+ <planned-activity id="a33a6a83-2b27-4678-a395-4025b399882b" details="Administer by phone" day="1">
79
+ <activity-reference code="941" source="Northwestern University"/>
80
+ </planned-activity>
81
+ </period>
82
+ </study-segment>
83
+ </epoch>
84
+ </add>
85
+ <add id="aefbcdc5-ac5b-4c0d-b092-b6e9e337969e" index="2">
86
+ <epoch id="9d7bf8eb-6413-4286-97c0-f44f489883e6" name="Run-in">
87
+ <study-segment id="14969b7b-e49e-48e0-b081-ba94d9448479" name="Run-in">
88
+ <period id="3970c8a8-89e3-4d7e-98ac-4f27232cc624" repetitions="3" start-day="1" duration-quantity="7" duration-unit="day">
89
+ <planned-activity id="cdd73e03-1410-4ae6-9d86-4a8929cd1678" day="1">
90
+ <activity-reference code="360" source="Northwestern University"/>
91
+ </planned-activity>
92
+ <planned-activity id="0df8ccf3-2067-47c6-bbf3-dfbf8512968e" day="7">
93
+ <activity-reference code="593" source="Northwestern University"/>
94
+ </planned-activity>
95
+ </period>
96
+ </study-segment>
97
+ </epoch>
98
+ </add>
99
+ <reorder id="a455e585-1bee-4770-b191-63fb8ec70066" child-id="9d7bf8eb-6413-4286-97c0-f44f489883e6" old-index="2" new-index="0"/>
100
+ </planned-calendar-delta>
101
+ </amendment>
102
+ <sources>
103
+ <source name="Northwestern University">
104
+ <activity name="Ketones (Acetone)" code="593" type="Lab Test"/>
105
+ <activity name="Taxol" code="211" type="Intervention"/>
106
+ <activity name="Dialysis Chemistry Panel" code="451" type="Lab Test"/>
107
+ <activity name="24 hr urine, protein electrophoresis" code="253" type="Lab Test"/>
108
+ <activity name="Carboplatin" code="43" type="Intervention"/>
109
+ <activity name="Pregnancy Test" code="701" type="Lab Test"/>
110
+ <activity name="CBC" code="360" type="Lab Test"/>
111
+ <activity name="QOL Survey" code="941" type="Other"/>
112
+ <activity name="Surgery" code="1041" type="Procedure"/>
113
+ </source>
114
+ </sources>
115
+ </study>
@@ -0,0 +1,64 @@
1
+ <!-- To rebuild the integration test PSC when you change this data, run `rake int-psc:rebuild` -->
2
+
3
+ <psc-state>
4
+ <!--
5
+ General note: Anywhere a date is specified, the value may either
6
+ be a date string in the form yyyy-mm-dd or an integer. An
7
+ integer indicates a date relative to today (negative, before
8
+ today; positive, after today).
9
+ -->
10
+
11
+ <site name="Northwestern University" assigned-identifier="IL036"/>
12
+ <site name="Mayo Clinic Rochester" assigned-identifier="MN026"/>
13
+ <site name="Thomas Jefferson University" assigned-identifier="PA121"/>
14
+
15
+ <!--
16
+ The assigned-identifier attribute for template is mandatory;
17
+ file is optional. If the file is omitted, it is assumed to be a
18
+ file named [assigned-identifier].xml in the same directory as
19
+ this state XML file.
20
+ -->
21
+ <template assigned-identifier="ABC 1200">
22
+ <!--
23
+ approval indicates whether the template should be marked as
24
+ approved for use by the site. It can be either a date or
25
+ false; the default is 0 (i.e., today). All released amendments
26
+ will have the same approval status.
27
+ -->
28
+ <participating-site assigned-identifier="IL036" approval="2008-01-07"/>
29
+ <participating-site assigned-identifier="PA121" approval="2010-01-02"/>
30
+ </template>
31
+
32
+
33
+ <registration>
34
+ <subject
35
+ first-name="Jo"
36
+ last-name="Fredricksson"
37
+ gender="Female"
38
+ birth-date="1950-06-01"
39
+ person-id="XC56700077"
40
+ >
41
+ <subject-property name="Hat size" value="7"/>
42
+ </subject>
43
+ <!-- template-identifier and site-identifier are mandatory attributes -->
44
+ <study-site
45
+ template="ABC 1200"
46
+ site="IL036"
47
+ study-subject-identifier="A0001"
48
+ desired-assignment-identifier="POP-2702">
49
+ <!--
50
+ * segment is either the ID for the segment or its "epoch: segment" name (mandatory).
51
+ * start is the start date for the segment (default: 0 for the first segment;
52
+ the end of the previous for subsequent). [TODO: the second part isn't implemented yet]
53
+ * mode is the transition mode for the segment (default: per-protocol).
54
+ -->
55
+ <scheduled-segment segment="Run-in" start="2010-01-01"/>
56
+ <scheduled-segment segment="Treatment: A" start="2010-02-01" mode="per-protocol"/>
57
+ <scheduled-segment segment="Follow up" start="2010-03-15" mode="immediate"/>
58
+ </study-site>
59
+
60
+ <!-- multiple study-sites allowed per registration to reuse the same subject -->
61
+ </registration>
62
+
63
+ <!-- multiple registrations allowed -->
64
+ </psc-state>
@@ -0,0 +1,47 @@
1
+ require 'builder'
2
+
3
+ ##
4
+ # The namespace for `psc.rb`.
5
+ module Psc
6
+ autoload :Faraday, 'psc/faraday'
7
+ autoload :Client, 'psc/client'
8
+ autoload :Connection, 'psc/connection'
9
+
10
+ ##
11
+ # Wraps `Builder::XmlMarkup` to ease the construction of PSC XML
12
+ # entities. For example:
13
+ #
14
+ # Psc.xml('study-snapshot', :assigned_identifier => 'YUV 1234') do |snap|
15
+ # snap.tag!('long-title', 'Why you validly counting?')
16
+ # snap.tag!('planned-calendar') { |pc|
17
+ # pc.epoch(:name => 'Run-in') { |e|
18
+ # # and so on
19
+ # }
20
+ # }
21
+ # snap.sources { |sources|
22
+ # sources.source { |src|
23
+ # # and so on
24
+ # }
25
+ # }
26
+ # }
27
+ #
28
+ # @see http://builder.rubyforge.org/classes/Builder/XmlMarkup.html
29
+ # @return [String] the constructed XML
30
+ def self.xml(root_name, root_attributes={}, &block)
31
+ root_attributes['xmlns'] = xml_namespace['psc']
32
+ Builder::XmlMarkup.new(:indent => 2).tag!(root_name, root_attributes, &block)
33
+ end
34
+
35
+ ##
36
+ # @private
37
+ XML_NAMESPACE = { 'psc' => 'http://bioinformatics.northwestern.edu/ns/psc' }.freeze
38
+
39
+ ##
40
+ # Provides an XML namespace mapping suitable for use with
41
+ # Nokogiri. The prefix `psc` is mapped to PSC's namespace.
42
+ #
43
+ # @return [Hash<String, String>] the mapping
44
+ def self.xml_namespace
45
+ XML_NAMESPACE
46
+ end
47
+ end
@@ -0,0 +1,35 @@
1
+ require 'psc'
2
+
3
+ module Psc
4
+ ##
5
+ # A high-level interface to a PSC instance's API. This class does
6
+ # not expose everything you can do with the API &mdash; only a few
7
+ # of the more common elements. Refer to the API documentation and
8
+ # use {Psc::Connection} for complete access.
9
+ class Client
10
+ ##
11
+ # The connection that the client is using to access PSC. Use it to
12
+ # make requests that the high-level interface doesn't support.
13
+ #
14
+ # @return [Psc::Connection]
15
+ attr_reader :connection
16
+
17
+ ##
18
+ # Create a new client instance. The given url and options will be
19
+ # used to create a {Psc::Connection} for the client to use; see
20
+ # that class for more details about what is permitted
21
+ def initialize(url, options, &block)
22
+ @connection = Psc::Connection.new(url, options, &block)
23
+ end
24
+
25
+ ##
26
+ # Returns an array of hashes describing the studies in the system.
27
+ # The contents are from the JSON representation of the `/studies`
28
+ # resource.
29
+ #
30
+ # @return [Array<Hash>]
31
+ def studies
32
+ connection.get('studies.json').body['studies']
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,96 @@
1
+ require 'psc'
2
+ require 'faraday'
3
+ require 'faraday_stack'
4
+
5
+ module Psc
6
+ ##
7
+ # A `Faraday::Connection` set up for use with Patient Study
8
+ # Calendar. See the {file:README.md} for a couple of examples.
9
+ #
10
+ # @see https://github.com/technoweenie/faraday
11
+ # @see https://github.com/mislav/faraday-stack
12
+ class Connection < ::Faraday::Connection
13
+ ##
14
+ # Create a new PSC connection. This is a `Faraday::Connection`
15
+ # with the following middleware:
16
+ #
17
+ # * Either {Psc::Faraday::HttpBasic} or {Psc::Faraday::PscToken}
18
+ # depending on the contents of the `:authenticator` option
19
+ # * {Psc::Faraday::StringIsXml}
20
+ # * `::Faraday::Request::JSON`
21
+ # * `::Faraday::Request::UrlEncoded`
22
+ # * `::FaradayStack::ResponseXML` for content-type text/xml
23
+ # * `::FaradayStack::ResponseJSON` for content-type application/json
24
+ # * `::Faraday::Adapter::NetHttp`
25
+ #
26
+ # If a block is provided, it will receive the Faraday builder so
27
+ # that you can append more middleware. If you provide your own
28
+ # adapter, the `net/http` adapter will not be appended.
29
+ #
30
+ # @param [String] url the base URL for your PSC instance
31
+ # @param [Hash] options the options for the connection. These are
32
+ # same as accepted by `Faraday::Connection`, plus:
33
+ # @option options [Hash] :authenticator parameters for the
34
+ # authentication middleware. These are detailed in the {file:README.md}.
35
+ # @yield [builder] (optional)
36
+ def initialize(url, options)
37
+ super do |builder|
38
+ builder.use *authentication_middleware(options[:authenticator])
39
+ builder.use Psc::Faraday::StringIsXml
40
+ builder.request :json
41
+ builder.request :url_encoded
42
+ builder.use FaradayStack::ResponseXML, :content_type => 'text/xml'
43
+ builder.use FaradayStack::ResponseJSON, :content_type => 'application/json'
44
+
45
+ if block_given?
46
+ yield builder
47
+ end
48
+
49
+ builder.adapter :net_http unless has_adapter?(builder)
50
+ end
51
+
52
+ unless self.path_prefix =~ %r{/api/v1$}
53
+ self.path_prefix = if self.path_prefix == '/'
54
+ '/api/v1'
55
+ else
56
+ self.path_prefix + '/api/v1'
57
+ end
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def authentication_middleware(authenticator)
64
+ unless authenticator
65
+ raise 'No authentication method specified. Please include the :authenticator option.'
66
+ end
67
+
68
+ kind = authenticator.keys.first
69
+
70
+ case kind
71
+ when :basic
72
+ [Psc::Faraday::HttpBasic, *authenticator[kind]]
73
+ when :token
74
+ [Psc::Faraday::PscToken, authenticator[kind]]
75
+ else
76
+ raise "Unsupported authentication method #{kind.inspect}."
77
+ end
78
+ end
79
+
80
+ def has_adapter?(builder)
81
+ builder.handlers.detect { |h| has_superclass?(h.klass, ::Faraday::Adapter) }
82
+ end
83
+
84
+ # It seems like there must be a builtin for this, but I'm not
85
+ # finding it.
86
+ def has_superclass?(child, ancestor)
87
+ if child.superclass == ancestor
88
+ true
89
+ elsif child.superclass.nil?
90
+ false
91
+ else
92
+ has_superclass?(child.superclass, ancestor)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,11 @@
1
+ require 'psc'
2
+
3
+ require 'faraday'
4
+
5
+ ##
6
+ # The custom Faraday middleware used in `psc.rb`.
7
+ module Psc::Faraday
8
+ autoload :HttpBasic, 'psc/faraday/http_basic'
9
+ autoload :PscToken, 'psc/faraday/psc_token'
10
+ autoload :StringIsXml, 'psc/faraday/string_is_xml'
11
+ end
@@ -0,0 +1,35 @@
1
+ require 'psc/faraday'
2
+
3
+ require 'base64'
4
+
5
+ module Psc::Faraday
6
+ ##
7
+ # Faraday middleware that implements [HTTP Basic][]. This is not
8
+ # PSC-specific, and Faraday even includes HTTP Basic support, but
9
+ # Faraday's support is not implemented as middleware. Using
10
+ # middleware makes setting up a connection based on the
11
+ # `:authenticator` option cleaner.
12
+ #
13
+ # [HTTP Basic]: http://www.ietf.org/rfc/rfc2617.txt
14
+ class HttpBasic
15
+ ##
16
+ # Create an instance of the middleware.
17
+ #
18
+ # @param [#call] app
19
+ # @param [String] username
20
+ # @param [String] password
21
+ def initialize(app, username, password)
22
+ @app = app
23
+ @header_value = "Basic #{Base64.encode64([username, password].join(':')).strip}"
24
+ end
25
+
26
+ ##
27
+ # Sets the `Authorization` request header using the HTTP Basic
28
+ # scheme.
29
+ def call(env)
30
+ env[:request_headers]['Authorization'] = @header_value
31
+
32
+ @app.call(env)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,42 @@
1
+ require 'psc/faraday'
2
+
3
+ module Psc
4
+ module Faraday
5
+ ##
6
+ # Faraday middleware that implements the `psc_token`
7
+ # authentication type. Tokens may either be static or computed
8
+ # per request.
9
+ class PscToken
10
+ ##
11
+ # Create a new instance of the middleware.
12
+ #
13
+ # @param [#call] app
14
+ # @param [#call,String] token_or_creator if the value for this
15
+ # parameter responds to `call`, it will be called to create a
16
+ # token on each request. Otherwise it will be used as a static
17
+ # token value.
18
+ def initialize(app, token_or_creator)
19
+ @app = app
20
+ if token_or_creator.respond_to?(:call)
21
+ @token_creator = token_or_creator
22
+ else
23
+ @token_creator = lambda { token_or_creator }
24
+ end
25
+ end
26
+
27
+ ##
28
+ # Adds the `Authorization` header using the configured token creator.
29
+ def call(env)
30
+ env[:request_headers]['Authorization'] = "psc_token #{token}"
31
+
32
+ @app.call
33
+ end
34
+
35
+ private
36
+
37
+ def token
38
+ @token_creator.call
39
+ end
40
+ end
41
+ end
42
+ end