foto 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,6 +3,8 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .rspec
7
+ .rbenv-version
6
8
  Gemfile.lock
7
9
  InstalledFiles
8
10
  _yardoc
@@ -12,6 +14,7 @@ lib/bundler/man
12
14
  pkg
13
15
  rdoc
14
16
  spec/reports
17
+ tags
15
18
  test/tmp
16
19
  test/version_tmp
17
20
  tmp
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Foto
2
2
 
3
- TODO: Write a gem description
3
+ A gem for communicating with the FOTO Patient Inquiry API http://share.patient-inquiry.com.
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,7 +18,39 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ ### Configure the gem:
22
+ ```ruby
23
+ Foto.configure do |config|
24
+ config.api_key = '41B4333G-FF2E-41B9-2M24-2G31381D237T'
25
+ config.base_uri = 'http://devs.patient-inquiry.com'
26
+ end
27
+ ```
28
+
29
+ ### Update or create a patient:
30
+ ```ruby
31
+ foto_patient = Foto::Patient.new({
32
+ :first_name => patient.first_name,
33
+ :last_name => patient.last_name,
34
+ :date_of_birth => patient.birth_date,
35
+ :email => patient.email,
36
+ :gender => patient.gender,
37
+ :language => 'en',
38
+ :external_id => patient.id
39
+ })
40
+ foto_patient.save
41
+ ```
42
+
43
+ ### You can also specify an api key per request:
44
+ ```ruby
45
+ foto_patient = Foto::Patient.new({
46
+ :api_key => '41B4333G-FF2E-41B9-2M24-2G31381D237T',
47
+ :first_name => patient.first_name,
48
+ :last_name => patient.last_name,
49
+ ...
50
+ })
51
+ foto_patient.save
52
+ ```
53
+
22
54
 
23
55
  ## Contributing
24
56
 
@@ -8,9 +8,14 @@ Gem::Specification.new do |gem|
8
8
  gem.version = Foto::VERSION
9
9
  gem.authors = ["Peter Tran"]
10
10
  gem.email = ["Peter Tran <ptran@optimiscorp.com>"]
11
- gem.description = %q{placeholder}
12
- gem.summary = %q{placeholder}
13
- gem.homepage = ""
11
+ gem.description = %q{Provides an interface for communicating with FOTO Patient Inquiry API}
12
+ gem.summary = %q{Provides an interface for communicating with FOTO Patient Inquiry API}
13
+ gem.homepage = "https://github.com/optimis/foto"
14
+
15
+ gem.add_dependency "yajl-ruby"
16
+ gem.add_dependency "nokogiri"
17
+ gem.add_development_dependency "rspec"
18
+ gem.add_development_dependency "webmock"
14
19
 
15
20
  gem.files = `git ls-files`.split($/)
16
21
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -1,5 +1,12 @@
1
- require "foto/version"
1
+ require 'foto/version'
2
2
 
3
3
  module Foto
4
- # Your code goes here...
4
+ require 'foto/client'
5
+ require 'foto/config'
6
+ require 'foto/consumer'
7
+ require 'foto/patient'
8
+ require 'foto/requests/request'
9
+ require 'foto/requests/response'
10
+ require 'foto/requests/put'
11
+ require 'foto/json_date'
5
12
  end
@@ -0,0 +1,15 @@
1
+ require 'foto/config'
2
+
3
+ module Foto
4
+ class Client
5
+ attr_accessor *Foto::Config::VALID_OPTIONS
6
+
7
+ def initialize(options={})
8
+ settings = Foto::Config.options.merge(options)
9
+
10
+ Config::VALID_OPTIONS.each do |option|
11
+ send("#{option}=", settings[option])
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ module Foto
2
+
3
+ def self.configure
4
+ yield Config
5
+ end
6
+
7
+ module Config
8
+ module Defaults
9
+ API_KEY = 'placeholder'
10
+ BASE_URI = 'http://devs.patient-inquiry.com'
11
+ end
12
+
13
+ extend self
14
+
15
+ VALID_OPTIONS = [:api_key, :base_uri]
16
+
17
+ attr_accessor *VALID_OPTIONS
18
+
19
+ def reset!
20
+ self.api_key = Defaults::API_KEY
21
+ self.base_uri = Defaults::BASE_URI
22
+ end
23
+
24
+ def options
25
+ Hash[ *VALID_OPTIONS.map {|option| [option, send(option)]}.flatten ]
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ module Foto
2
+ class Consumer
3
+ attr_accessor :api_key
4
+
5
+ def self.url
6
+ raise NotImplementedError.new('You must implement self.url')
7
+ end
8
+
9
+ def initialize(attributes={})
10
+ attributes.each do |k, v|
11
+ send("#{k}=", v)
12
+ end
13
+ end
14
+
15
+ def as_json
16
+ raise NotImplementedError.new('You must implement as_json')
17
+ end
18
+
19
+ def save
20
+ put = Foto::Requests::Put.new(self, as_json)
21
+ put.run
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ class Foto::JsonDate
2
+ attr_accessor :date
3
+
4
+ def initialize(date)
5
+ @date = date
6
+ end
7
+
8
+ def to_json
9
+ format = "\"\\/Date(%s)\\/\""
10
+ format % [date.strftime("%s%z")]
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ module Foto
2
+ class Patient < Foto::Consumer
3
+ ATTRIBUTES = [ :external_id, :first_name, :last_name,
4
+ :email, :date_of_birth, :gender, :language ]
5
+
6
+ attr_accessor *ATTRIBUTES
7
+
8
+ class << self
9
+ def attributes
10
+ ATTRIBUTES
11
+ end
12
+
13
+ def url
14
+ 'patient'
15
+ end
16
+ end
17
+
18
+ def as_json
19
+ Yajl::Encoder.encode({
20
+ 'FirstName' => first_name,
21
+ 'LastName' => last_name,
22
+ 'DateOfBirth' => Foto::JsonDate.new(date_of_birth),
23
+ 'Email' => email,
24
+ 'Gender' => gender,
25
+ 'Language' => language || 'en',
26
+ 'ExternalId' => external_id
27
+ })
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'foto/requests/request'
2
+
3
+ module Foto
4
+ module Requests
5
+ class Put < Foto::Requests::Request
6
+
7
+ private
8
+
9
+ def build_http_request
10
+ request = Net::HTTP::Put.new(url.request_uri)
11
+ request.body = body
12
+ request
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,68 @@
1
+ module Foto
2
+ module Requests
3
+ class Request
4
+ attr_accessor :relative_url, :body, :consumer
5
+
6
+ def initialize(consumer, body = {})
7
+ @consumer = consumer
8
+ @relative_url = consumer.class.url
9
+ @body = body
10
+ end
11
+
12
+ def run
13
+ send_http_request
14
+ end
15
+
16
+ def url
17
+ @url ||= build_url
18
+ end
19
+
20
+ private
21
+
22
+ def build_http_request
23
+ raise NotImplementedError.new('You must implement build_request')
24
+ end
25
+
26
+ def http_request
27
+ @http_request ||= add_headers(build_http_request)
28
+ end
29
+
30
+ def protocol
31
+ url.scheme
32
+ end
33
+
34
+ def content_length
35
+ body.length
36
+ end
37
+
38
+ def content_type
39
+ 'text/json'
40
+ end
41
+
42
+ def api_key
43
+ consumer.api_key || Foto::Config.api_key
44
+ end
45
+
46
+ def add_headers(http_request)
47
+ http_request.add_field('User-Agent', 'Foto')
48
+ http_request.add_field('Content-Length', content_length)
49
+ http_request.add_field('Content-Type', content_type)
50
+ http_request
51
+ end
52
+
53
+ def send_http_request
54
+ base_uri = URI(Foto::Config.base_uri)
55
+ http = Net::HTTP.new(base_uri.host, base_uri.port)
56
+ http.use_ssl = (protocol === 'https')
57
+ http.start do |http|
58
+ Response.new(http.request(http_request))
59
+ end
60
+ end
61
+
62
+ def build_url
63
+ format = 'json'
64
+ URI("#{Foto::Config.base_uri}/#{relative_url}/#{format}/?Api-Key=#{api_key}")
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,21 @@
1
+ module Foto
2
+ module Requests
3
+ class Response
4
+ attr_reader :body, :code
5
+
6
+ def initialize(http_response)
7
+ @body = http_response.body
8
+ @code = http_response.code
9
+ end
10
+
11
+ def message
12
+ doc = Nokogiri::HTML(@body)
13
+ doc.xpath('/html/body/p').first.content
14
+ end
15
+
16
+ def successful?
17
+ code == '200'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Foto
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Foto::Client do
4
+ describe '#initialize' do
5
+ let(:default_options) do
6
+ { :api_key => 'AAABBBCCC', :base_uri => 'http://a.b.com' }
7
+ end
8
+ let(:foto) { Foto::Client.new(default_options) }
9
+
10
+ it 'can accept a default options hash' do
11
+ foto.api_key.should eql(default_options[:api_key])
12
+ foto.base_uri.should eql(default_options[:base_uri])
13
+ end
14
+ end
15
+ end
16
+
17
+
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Foto::Config do
4
+ let(:config) { Foto::Config }
5
+ let(:defaults) { Foto::Config::Defaults }
6
+
7
+ before do
8
+ config.reset!
9
+ end
10
+
11
+ describe '.api_key' do
12
+ it 'has a default' do
13
+ config.api_key.should eql(defaults::API_KEY)
14
+ end
15
+ end
16
+
17
+ describe '.base_uri' do
18
+ it 'has a default' do
19
+ config.base_uri.should eql(defaults::BASE_URI)
20
+ end
21
+ end
22
+
23
+ describe '.reset!' do
24
+ it 'resets the configuration to their default values' do
25
+ config.api_key = 'somethingelse'
26
+ config.api_key.should eql('somethingelse')
27
+ config.base_uri = 'http://other.com'
28
+ config.base_uri.should eql('http://other.com')
29
+ config.reset!
30
+ config.api_key.should eql(defaults::API_KEY)
31
+ config.base_uri.should eql(defaults::BASE_URI)
32
+ end
33
+ end
34
+
35
+ describe '.options' do
36
+ it 'returns a hash of current options' do
37
+ config.options.keys.should =~ Foto::Config::VALID_OPTIONS
38
+ end
39
+ end
40
+ end
41
+
42
+ describe Foto do
43
+ describe '.configure' do
44
+ Foto::Config::VALID_OPTIONS.each do |option|
45
+ it "#{option} should be configurable" do
46
+ Foto.configure do |configuration|
47
+ configuration.send("#{option}=", option)
48
+ configuration.send(option).should eql(option)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Foto do
4
+ it 'should have a version' do
5
+ Foto::VERSION.should_not be_nil
6
+ end
7
+ end
8
+
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Foto::Patient do
4
+ let(:patient) { Foto::Patient.new }
5
+ let(:initialized_patient) { Foto::Patient.new(patient_attributes) }
6
+ let(:patient_attributes) do
7
+ {
8
+ :external_id => 'external_id_test',
9
+ :first_name => 'Bob',
10
+ :last_name => 'Bobson',
11
+ :email => 'bob.bobson@bobbobson.com',
12
+ :date_of_birth => Time.parse('03/07/1983'),
13
+ :gender => 'M',
14
+ :language => 'en'
15
+ }
16
+ end
17
+
18
+ it 'should have accessors for each attribute' do
19
+ Foto::Patient.attributes.each do |attribute|
20
+ patient.should respond_to(attribute)
21
+ end
22
+ end
23
+
24
+ it 'accepts an initial hash of attributes' do
25
+ patient_attributes.each do |k, v|
26
+ v.should_not be_nil
27
+ initialized_patient.send(k).should eql(v)
28
+ end
29
+ end
30
+
31
+ describe '#as_json' do
32
+ let(:date_of_birth) { Foto::JsonDate.new(initialized_patient.date_of_birth).to_json }
33
+ it 'returns a JSON hash of attributes' do
34
+ Yajl::Parser.parse(initialized_patient.as_json).should == {
35
+ 'FirstName' => initialized_patient.first_name,
36
+ 'LastName' => initialized_patient.last_name,
37
+ 'DateOfBirth' => Yajl::Parser.parse(date_of_birth),
38
+ 'Email' => initialized_patient.email,
39
+ 'Gender' => initialized_patient.gender,
40
+ 'Language' => initialized_patient.language,
41
+ 'ExternalId' => initialized_patient.external_id
42
+ }
43
+ end
44
+ end
45
+
46
+ describe '#save' do
47
+ let(:request) { mock :request }
48
+ it 'makes a request to FOTO' do
49
+ Foto::Requests::Put.should_receive(:new).and_return(request)
50
+ request.should_receive(:run)
51
+ initialized_patient.save
52
+ end
53
+ end
54
+
55
+ describe '.url' do
56
+ it 'returns a partial URL' do
57
+ patient.class.url.should_not be_nil
58
+ patient.class.url.should be_an_instance_of(String)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Foto::Requests::Put do
4
+ let(:patient) { Foto::Patient.new }
5
+ let(:url) { Foto::Requests::Put.new(patient).send(:build_url).to_s }
6
+ let(:body) do
7
+ {
8
+ :a => 'a',
9
+ :b => 'b',
10
+ :c => 'c'
11
+ }
12
+ end
13
+ let(:error) do
14
+ %q{
15
+ <html>
16
+ <head>
17
+ <title>Request Error - No API Key</title>
18
+ <style type="text/css">
19
+ body
20
+ {
21
+ font-family: Verdana;
22
+ font-size: x-large;
23
+ }
24
+ </style>
25
+ </head>
26
+ <body>
27
+ <h1>Request Error</h1>
28
+ <p>A valid API key needs to be included using the Api-Key query string parameter</p>
29
+ </body>
30
+ </html>}
31
+ end
32
+
33
+ describe '#run' do
34
+ describe 'On success' do
35
+ it 'makes an HTTP Put request to the correct URL' do
36
+ stub_request(:put, url)
37
+ Foto::Requests::Put.new(patient, body).run
38
+ assert_requested(:put, url)
39
+ end
40
+ end
41
+
42
+ describe 'On error' do
43
+ it 'returns an instance of Foto::Requests::Response' do
44
+ stub_request(:put, url).to_return(:body => error, :status => 401)
45
+ response = Foto::Requests::Put.new(patient, body).run
46
+ assert_requested(:put, url)
47
+ response.message.should eql('A valid API key needs to be included using the Api-Key query string parameter')
48
+ response.code.should eql('401')
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#url' do
54
+ let(:api_key) { Foto::Config.api_key }
55
+ let(:base_uri) { Foto::Config.base_uri }
56
+ let(:uri) { Foto::Requests::Put.new(patient).send(:build_url) }
57
+
58
+ it 'returns a URI::HTTP' do
59
+ uri.class.should eql(URI::HTTP)
60
+ end
61
+
62
+ it 'has the correct url' do
63
+ uri.to_s.should eql("#{base_uri}/#{patient.class.url}/json/?Api-Key=#{api_key}")
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Foto::Requests::Response do
4
+ let(:http_response) do
5
+ mock :http_response, :body => html, :code => '401'
6
+ end
7
+ let(:html) do
8
+ %q{
9
+ <html>
10
+ <head>
11
+ <title>Request Error - No API Key</title>
12
+ <style type="text/css">
13
+ body
14
+ {
15
+ font-family: Verdana;
16
+ font-size: x-large;
17
+ }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <h1>Request Error</h1>
22
+ <p>A valid API key needs to be included using the Api-Key query string parameter</p>
23
+ </body>
24
+ </html>}
25
+ end
26
+ let!(:response) { Foto::Requests::Response.new(http_response) }
27
+
28
+ describe '#initialize' do
29
+ it 'sets the appropriate instance variables' do
30
+ response.body.should eql(html)
31
+ response.code.should eql('401')
32
+ end
33
+ end
34
+
35
+ describe '#message' do
36
+ it 'returns the correct response message' do
37
+ response.message.should eql('A valid API key needs to be included using the Api-Key query string parameter')
38
+ end
39
+ end
40
+
41
+ describe 'successful?' do
42
+ it 'returns true if the request was successful' do
43
+ response.should_not be_successful
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,26 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require 'yajl'
8
+ require 'nokogiri'
9
+ require 'foto'
10
+ require 'webmock/rspec'
11
+
12
+ RSpec.configure do |config|
13
+ config.treat_symbols_as_metadata_keys_with_true_values = true
14
+ config.run_all_when_everything_filtered = true
15
+ config.filter_run :focus
16
+
17
+ # Run specs in random order to surface order dependencies. If you find an
18
+ # order dependency and want to debug it, you can fix the order by providing
19
+ # the seed, which is printed after each run.
20
+ # --seed 1234
21
+ config.order = 'random'
22
+
23
+ config.before(:each) do
24
+ Foto::Config.reset!
25
+ end
26
+ end
metadata CHANGED
@@ -1,23 +1,88 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: foto
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Peter Tran
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-11-13 00:00:00.000000000 Z
13
- dependencies: []
14
- description: placeholder
15
- email:
17
+
18
+ date: 2012-12-06 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: yajl-ruby
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: nokogiri
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: webmock
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :development
75
+ version_requirements: *id004
76
+ description: Provides an interface for communicating with FOTO Patient Inquiry API
77
+ email:
16
78
  - Peter Tran <ptran@optimiscorp.com>
17
79
  executables: []
80
+
18
81
  extensions: []
82
+
19
83
  extra_rdoc_files: []
20
- files:
84
+
85
+ files:
21
86
  - .gitignore
22
87
  - Gemfile
23
88
  - LICENSE.txt
@@ -25,29 +90,61 @@ files:
25
90
  - Rakefile
26
91
  - foto.gemspec
27
92
  - lib/foto.rb
93
+ - lib/foto/client.rb
94
+ - lib/foto/config.rb
95
+ - lib/foto/consumer.rb
96
+ - lib/foto/json_date.rb
97
+ - lib/foto/patient.rb
98
+ - lib/foto/requests/put.rb
99
+ - lib/foto/requests/request.rb
100
+ - lib/foto/requests/response.rb
28
101
  - lib/foto/version.rb
29
- homepage: ''
102
+ - spec/foto/client_spec.rb
103
+ - spec/foto/config_spec.rb
104
+ - spec/foto/foto_spec.rb
105
+ - spec/foto/patient_spec.rb
106
+ - spec/foto/requests/put_spec.rb
107
+ - spec/foto/requests/response_spec.rb
108
+ - spec/spec_helper.rb
109
+ homepage: https://github.com/optimis/foto
30
110
  licenses: []
111
+
31
112
  post_install_message:
32
113
  rdoc_options: []
33
- require_paths:
114
+
115
+ require_paths:
34
116
  - lib
35
- required_ruby_version: !ruby/object:Gem::Requirement
117
+ required_ruby_version: !ruby/object:Gem::Requirement
36
118
  none: false
37
- requirements:
38
- - - ! '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
127
  none: false
43
- requirements:
44
- - - ! '>='
45
- - !ruby/object:Gem::Version
46
- version: '0'
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
47
135
  requirements: []
136
+
48
137
  rubyforge_project:
49
- rubygems_version: 1.8.23
138
+ rubygems_version: 1.8.15
50
139
  signing_key:
51
140
  specification_version: 3
52
- summary: placeholder
53
- test_files: []
141
+ summary: Provides an interface for communicating with FOTO Patient Inquiry API
142
+ test_files:
143
+ - spec/foto/client_spec.rb
144
+ - spec/foto/config_spec.rb
145
+ - spec/foto/foto_spec.rb
146
+ - spec/foto/patient_spec.rb
147
+ - spec/foto/requests/put_spec.rb
148
+ - spec/foto/requests/response_spec.rb
149
+ - spec/spec_helper.rb
150
+ has_rdoc: