Skip to content

Commit

Permalink
Merge pull request #169 from fhir-crucible/FI-2906-R4B-support
Browse files Browse the repository at this point in the history
FI-2906 R4B and R5 support
  • Loading branch information
360dgries authored Oct 18, 2024
2 parents b1fff31 + 33030ae commit 8fec066
Show file tree
Hide file tree
Showing 17 changed files with 531 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['2.6', '2.7']
ruby-version: ['3.0', '3.1', '3.2']

steps:
- uses: actions/checkout@v2
Expand Down
8 changes: 1 addition & 7 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
inherit_from: .rubocop_todo.yml

AllCops:
TargetRubyVersion: 2.4
TargetRubyVersion: 3.0
Exclude:
- '*.gemspec'
- 'Gemfile*'
Expand All @@ -10,9 +10,6 @@ AllCops:
- 'lib/tasks/*'
- 'vendor/**/*'

Documentation:
Enabled: false

Metrics:
Enabled: false

Expand All @@ -22,8 +19,5 @@ Style:
Layout:
Enabled: false

Performance/Casecmp:
Enabled: false

Naming:
Enabled: false
14 changes: 1 addition & 13 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2019-03-22 01:56:17 -0400 using RuboCop version 0.52.1.
# on 2024-10-14 14:56:48 UTC using RuboCop version 1.23.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 4
# Cop supports --auto-correct.
Performance/RegexpMatch:
Exclude:
- 'lib/fhir_client/model/client_reply.rb'

# Offense count: 197
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 210
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ source 'https://rubygems.org'
gemspec

group :test do
gem 'rubocop', '~> 0.52.1', require: false
gem 'rubocop', '~> 1.23.0', require: false
gem 'awesome_print', require: 'ap'
end
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Ruby FHIR client.

Supports:
* FHIR R4, STU3 and DSTU2
* FHIR R5, R4B, R4, STU3 and DSTU2
* JSON and XML
* All CRUD, including version read and history
* Transactions and Batches
Expand Down Expand Up @@ -59,7 +59,7 @@ patient.destroy
## Advanced Usage

### Changing FHIR Versions
The client defaults to `R4` but can be switched to `DSTU2` or `STU3`. It can also attempt to autodetect the FHIR version based on the `metadata` endpoint.
The client defaults to `R4` but can be switched to other versions. It can also attempt to autodetect the FHIR version based on the `metadata` endpoint.

```ruby
# autodetect the FHIR version
Expand All @@ -71,6 +71,10 @@ elsif version == :dstu2
puts 'FHIR Client using DSTU2'
elsif version == :r4
puts 'FHIR Client using R4'
elsif version == :r4b
puts 'FHIR Client using R4B'
elsif
puts 'FHIR Client using R5'
end

# tell the client to use R4
Expand All @@ -79,7 +83,7 @@ client.use_r4
patient = FHIR::Patient.read('example')
patient = client.read(FHIR::Patient, 'example').resource

# tell the client to use STU3 (default)
# tell the client to use STU3
client.use_stu3
# now use the client normally
patient = FHIR::STU3::Patient.read('example')
Expand Down
3 changes: 2 additions & 1 deletion fhir_client.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']

spec.required_ruby_version = '>= 3.0.0'
spec.add_dependency 'activesupport', '>= 3'
spec.add_dependency 'addressable', '>= 2.3'
spec.add_dependency 'fhir_models', '>= 4.2.1'
spec.add_dependency 'fhir_models', '>= 5.0.0'
spec.add_dependency 'fhir_stu3_models', '>= 3.1.1'
spec.add_dependency 'fhir_dstu2_models', '>= 1.1.1'
spec.add_dependency 'nokogiri', '>= 1.10.4'
Expand Down
2 changes: 2 additions & 0 deletions lib/fhir_client.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require 'fhir_models'
require 'fhir_models/r4b'
require 'fhir_models/r5'
require 'fhir_dstu2_models'
require 'fhir_stu3_models'
require 'active_support/all'
Expand Down
68 changes: 55 additions & 13 deletions lib/fhir_client/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ def use_r4
@default_format = versioned_format_class
end

def use_r4b
@fhir_version = :r4b
@default_format = versioned_format_class
end

def use_r5
@fhir_version = :r5
@default_format = versioned_format_class
end

#
# Instructs the client to specify the minimal Prefer Header where applicable
def use_minimal_preference
Expand All @@ -95,6 +105,10 @@ def detect_version
cap = capability_statement
if cap.is_a?(FHIR::CapabilityStatement)
use_r4
elsif cap.is_a?(FHIR::R4B::CapabilityStatement)
use_r4b
elsif cap.is_a?(FHIR::R5::CapabilityStatement)
use_r5
elsif cap.is_a?(FHIR::STU3::CapabilityStatement)
use_stu3
elsif cap.is_a?(FHIR::DSTU2::Conformance)
Expand Down Expand Up @@ -275,20 +289,36 @@ def try_conformance_formats(default_format)
rescue
@cached_capability_statement = nil
end
if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('4')
use_stu3
if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('4.0')
use_r4b
begin
@cached_capability_statement = parse_reply(FHIR::STU3::CapabilityStatement, frmt, reply)
@cached_capability_statement = parse_reply(FHIR::R4B::CapabilityStatement, frmt, reply)
rescue
@cached_capability_statement = nil
end
unless @cached_capability_statement
use_dstu2
if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('4')
use_r5
begin
@cached_capability_statement = parse_reply(FHIR::DSTU2::Conformance, frmt, reply)
@cached_capability_statement = parse_reply(FHIR::R5::CapabilityStatement, frmt, reply)
rescue
@cached_capability_statement = nil
end
if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('5')
use_stu3
begin
@cached_capability_statement = parse_reply(FHIR::STU3::CapabilityStatement, frmt, reply)
rescue
@cached_capability_statement = nil
end
unless @cached_capability_statement
use_dstu2
begin
@cached_capability_statement = parse_reply(FHIR::DSTU2::Conformance, frmt, reply)
rescue
@cached_capability_statement = nil
end
end
end
end
end
if @cached_capability_statement
Expand Down Expand Up @@ -317,23 +347,35 @@ def parse_reply(klass, format, response)
return nil unless [200, 201].include? response.code
res =
begin
if(@fhir_version == :dstu2 || klass&.ancestors&.include?(FHIR::DSTU2::Model))
if(@fhir_version == :dstu2 || klass < FHIR::DSTU2::Model)
if(format.include?('xml'))
FHIR::DSTU2::Xml.from_xml(response.body)
else
FHIR::DSTU2::Json.from_json(response.body)
end
elsif(@fhir_version == :r4 || klass&.ancestors&.include?(FHIR::Model))
elsif(@fhir_version == :stu3 || klass < FHIR::STU3::Model)
if(format.include?('xml'))
FHIR::Xml.from_xml(response.body)
FHIR::STU3::Xml.from_xml(response.body)
else
FHIR::Json.from_json(response.body)
FHIR::STU3::Json.from_json(response.body)
end
elsif(@fhir_version == :r4b || klass < FHIR::R4B::Model)
if(format.include?('xml'))
FHIR::R4B::Xml.from_xml(response.body)
else
FHIR::R4B::Json.from_json(response.body)
end
elsif(@fhir_version == :r5 || klass < FHIR::R5::Model)
if(format.include?('xml'))
FHIR::R5::Xml.from_xml(response.body)
else
FHIR::R5::Json.from_json(response.body)
end
else
if(format.include?('xml'))
FHIR::STU3::Xml.from_xml(response.body)
FHIR::Xml.from_xml(response.body)
else
FHIR::STU3::Json.from_json(response.body)
FHIR::Json.from_json(response.body)
end
end
rescue => e
Expand All @@ -349,7 +391,7 @@ def set_client_on_resource(resource)

resource.client = self
resource.each_element do |element, _, _|
if element.is_a?(Reference) || element.is_a?(STU3::Reference) || element.is_a?(DSTU2::Reference) || element.respond_to?(:resourceType)
if element.is_a?(Reference) || element.is_a?(FHIR::R4B::Reference) || element.is_a?(FHIR::R5::Reference) || element.is_a?(STU3::Reference) || element.is_a?(DSTU2::Reference) || element.respond_to?(:resourceType)
element.client = self
end
end
Expand Down
16 changes: 16 additions & 0 deletions lib/fhir_client/ext/bundle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,20 @@ class Bundle
include FHIR::BundleExtras
end
end
end

module FHIR
module R4B
class Bundle < FHIR::R4B::Model
include FHIR::BundleExtras
end
end
end

module FHIR
module R5
class Bundle < FHIR::R5::Model
include FHIR::BundleExtras
end
end
end
16 changes: 16 additions & 0 deletions lib/fhir_client/ext/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,19 @@ class Model
end
end
end

module FHIR
module R4B
class Model < FHIR::Model
include FHIR::ModelExtras
end
end
end

module FHIR
module R5
class Model < FHIR::Model
include FHIR::ModelExtras
end
end
end
32 changes: 28 additions & 4 deletions lib/fhir_client/ext/reference.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Reference
include FHIR::ReferenceExtras

def resource_class
"FHIR::#{resource_type}".constantize unless contained?
FHIR.const_get(resource_type) unless contained?
end
end
end
Expand All @@ -93,20 +93,44 @@ class Reference
include FHIR::ReferenceExtras

def resource_class
"FHIR::DSTU2::#{resource_type}".constantize unless contained?
FHIR::DSTU2.const_get(resource_type) unless contained?
end
end
end
end

module FHIR
module STU3
class Reference
class Reference
include FHIR::ReferenceExtras

def resource_class
FHIR::STU3.const_get(resource_type) unless contained?
end
end
end
end

module FHIR
module R4B
class Reference < FHIR::R4B::Model
include FHIR::ReferenceExtras

def resource_class
"FHIR::STU3::#{resource_type}".constantize unless contained?
FHIR::R4B.const_get(resource_type) unless contained?
end
end
end
end

module FHIR
module R5
class Reference < FHIR::R5::Model
include FHIR::ReferenceExtras

def resource_class
FHIR::R5.const_get(resource_type) unless contained?
end
end
end
end
4 changes: 4 additions & 0 deletions lib/fhir_client/version_management.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ def versioned_resource_class(klass = nil)
FHIR::STU3
when :dstu2
FHIR::DSTU2
when :r4b
FHIR::R4B
when :r5
FHIR::R5
else
FHIR
end
Expand Down
Loading

0 comments on commit 8fec066

Please sign in to comment.