ensconce 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +69 -0
  4. data/Rakefile +9 -0
  5. data/lib/ensconce.rb +10 -0
  6. data/lib/ensconce/adapters/adapter.rb +52 -0
  7. data/lib/ensconce/adapters/mydex_adapter.rb +75 -0
  8. data/lib/ensconce/adapters/yaml_file_adapter.rb +21 -0
  9. data/lib/ensconce/data_store.rb +41 -0
  10. data/lib/ensconce/hash_builder.rb +72 -0
  11. data/lib/ensconce/key_mappers/key_map.rb +35 -0
  12. data/lib/ensconce/key_mappers/mydex_key_map.rb +23 -0
  13. data/lib/ensconce/mangle.rb +31 -0
  14. data/lib/ensconce/version.rb +15 -0
  15. data/test/data/users.yml +9 -0
  16. data/test/ensconce/adapters/adapter_test.rb +22 -0
  17. data/test/ensconce/adapters/mydex_adapter_test.rb +49 -0
  18. data/test/ensconce/adapters/yaml_file_adapter_test.rb +31 -0
  19. data/test/ensconce/data_store_test.rb +72 -0
  20. data/test/ensconce/key_mappers/hash_builder_test.rb +102 -0
  21. data/test/ensconce/key_mappers/mydex_key_map_test.rb +20 -0
  22. data/test/ensconce/mangle_test.rb +25 -0
  23. data/test/fixtures/users.yml +9 -0
  24. data/test/fixtures/vcr_cassettes/datastore_after_mydex_adapter_test.yml +44 -0
  25. data/test/fixtures/vcr_cassettes/datastore_before_mydex_adapter_test.yml +85 -0
  26. data/test/fixtures/vcr_cassettes/datastore_get_Harry.yml +44 -0
  27. data/test/fixtures/vcr_cassettes/datastore_get_Mary.yml +44 -0
  28. data/test/fixtures/vcr_cassettes/datastore_get_Trevor.yml +44 -0
  29. data/test/fixtures/vcr_cassettes/datastore_push_Harry.yml +44 -0
  30. data/test/fixtures/vcr_cassettes/datastore_push_Mary.yml +44 -0
  31. data/test/fixtures/vcr_cassettes/datastore_push_Trevor.yml +44 -0
  32. data/test/fixtures/vcr_cassettes/datastore_test_get.yml +44 -0
  33. data/test/test_helper.rb +67 -0
  34. metadata +110 -0
@@ -0,0 +1,31 @@
1
+
2
+ module Ensconce
3
+ module Mangle
4
+
5
+ # Hash#merge will replace the value of a key with its replacement's value.
6
+ # If the value is itself a hash, the original is replaced.
7
+ # With deep_merge, if the value is a hash the original value is merged with
8
+ # the replacements.
9
+ # original = {one: {two: 2}, three: 3}
10
+ # replacement = {one: {four: 4}}
11
+ # original.merge(replacement) --> {one: {four: 4}, three: 3}
12
+ # Mangle.deep_merge(original, replacement) --> {one: {two: 2, four: 4}, three: 3}
13
+ def self.deep_merge(original, replacement)
14
+ if original.kind_of? Hash
15
+ original.merge(replacement){|key, oldval, newval| deep_merge(oldval, newval)}
16
+ else
17
+ replacement
18
+ end
19
+ end
20
+
21
+ # Changes the keys of a hash based on a hash. The map is a hash where the
22
+ # values are the old keys, and the values are the replacement keys
23
+ # original = {one: {two: 2}, three: 3}
24
+ # hash = {one: :four, three: :five}
25
+ # Mangle.rekey(original, hash) --> {four: {two: 2}, five: 3}
26
+ def self.rekey(hash, change_map)
27
+ change_map.each{|old, new| hash[new] = hash.delete(old)}
28
+ return hash
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ module Ensconce
2
+ VERSION = "0.0.2"
3
+ end
4
+
5
+ # History
6
+ # =======
7
+ #
8
+ # 0.0.2: Cleansed release
9
+ # -----------------------
10
+ # Re-release with settings.yml purged
11
+ #
12
+ # 0.0.1: First release
13
+ # --------------------
14
+ # Includes YAML and MyDex adapters.
15
+ #
@@ -0,0 +1,9 @@
1
+ user_1:
2
+ first_name: Bob
3
+ last_name: Bloggs
4
+ gender: Male
5
+
6
+ user_2:
7
+ first_name: Jane
8
+ last_name: Doe
9
+ gender: Female
@@ -0,0 +1,22 @@
1
+ require 'test/unit'
2
+ require_relative '../../../lib/ensconce'
3
+
4
+ module Ensconce
5
+ class AdapterTest < Test::Unit::TestCase
6
+ def test_config
7
+ stuff = {foo: 'bar'}
8
+ Adapter.config(stuff)
9
+ assert_equal(stuff, Adapter.options)
10
+ end
11
+
12
+ def test_method_holders
13
+ methods = %w{get push}
14
+ adapter = Adapter.new
15
+ methods.each do |method|
16
+ assert_raise RuntimeError, "Adapter.#{method} should raise an error." do
17
+ adapter.send method
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ensconce
4
+ class MydexAdapterTest < Test::Unit::TestCase
5
+ def setup
6
+
7
+ MydexAdapter.config(
8
+ url: settings['mydex']['url'],
9
+ api_key: settings['mydex']['api_key']
10
+ )
11
+ end
12
+
13
+ def test_adapter_for
14
+ user = TestUser.new(
15
+ :key => settings['mydex']['key'],
16
+ :con_id => settings['mydex']['con_id'],
17
+ :id => settings['mydex']['id']
18
+ )
19
+ @adapter = MydexAdapter.for(user, :data_set => 'field_ds_personal_details')
20
+ assert_equal(settings['mydex']['key'], @adapter.settings.key)
21
+ end
22
+
23
+
24
+
25
+ def test_get
26
+ test_adapter_for
27
+ VCR.use_cassette('datastore_test_get') do
28
+ data = @adapter.get
29
+ assert_equal(MydexKeyMap.field_ds_personal_details_map[:replacement], data.keys)
30
+ assert(data.values.collect{|v| v unless v.empty?}.compact.length > 0, "Values should not all be empty")
31
+ end
32
+ end
33
+
34
+ def test_push
35
+ values = %w{Harry Mary Trevor}
36
+ key = 'first_name'
37
+ test_adapter_for
38
+ values.each do |value|
39
+ VCR.use_cassette("datastore_push_#{value}") do
40
+ @adapter.push({key => value})
41
+ end
42
+ VCR.use_cassette("datastore_get_#{value}") do
43
+ result = @adapter.get
44
+ assert_equal(value, result[key])
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,31 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ensconce
4
+ class YamlFileAdapterTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @users = fixture['users']
8
+ YamlFileAdapter.config(
9
+ :file => data_path('users')
10
+ )
11
+ @user = TestUser.new(:id => 'user_1')
12
+ @adapter = YamlFileAdapter.for(@user)
13
+ end
14
+
15
+ def test_setup
16
+ assert_equal(current_data_for('users'), @users)
17
+ end
18
+
19
+ def test_get
20
+ assert_equal(@users[@user.id], @adapter.get)
21
+ end
22
+
23
+ def test_push
24
+ update = {"first_name" => 'Harry'}
25
+ @adapter.push(update)
26
+ @users[@user.id].merge!(update)
27
+ assert_equal(@users, current_data_for('users'))
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,72 @@
1
+ require_relative '../test_helper'
2
+
3
+ module Ensconce
4
+ class DataStoreTest < Test::Unit::TestCase
5
+ def setup
6
+ DataStore.adapter = YamlFileAdapter.config(:file => data_path('users'))
7
+ @users = fixture['users']
8
+ user = TestUser.new(id: 'user_1')
9
+ @data_store = DataStore.open user
10
+ end
11
+
12
+ def test_open
13
+ assert_equal(@users['user_1'], @data_store)
14
+ end
15
+
16
+ def test_save
17
+ name = 'Gillian'
18
+ @data_store['first_name'] = name
19
+ @data_store.save
20
+ @users['user_1'].merge!({'first_name' => name})
21
+ assert_equal(@users, current_data_for('users'))
22
+ end
23
+
24
+ def test_new
25
+ user = TestUser.new(id: 'user_99')
26
+ @user = {
27
+ user.id => {
28
+ 'first_name' => 'Ice',
29
+ 'last_name' => 'Cream',
30
+ 'gender' => 'female'
31
+ }
32
+ }
33
+ @data_store = DataStore.new(user, :data => @user[user.id])
34
+ assert_equal(@user[user.id], @data_store)
35
+ end
36
+
37
+ def test_create
38
+ test_new
39
+ @data_store.save
40
+ @users.merge! @user
41
+ assert_equal(@users, current_data_for('users'))
42
+ end
43
+
44
+ def test_with_mydex_adapter
45
+ DataStore.adapter = MydexAdapter.config(
46
+ url: settings['mydex']['url'],
47
+ api_key: settings['mydex']['api_key']
48
+ )
49
+ @user = TestUser.new(
50
+ :key => settings['mydex']['key'],
51
+ :con_id => settings['mydex']['con_id'],
52
+ :id => settings['mydex']['id']
53
+ )
54
+ VCR.use_cassette('datastore_before_mydex_adapter_test') do
55
+ @data_store = DataStore.open(
56
+ @user,
57
+ :data_set => 'field_ds_personal_details')
58
+ @name = 'Gillian'
59
+ @data_store['first_name'] = @name
60
+ @data_store.save
61
+ end
62
+ VCR.use_cassette('datastore_after_mydex_adapter_test') do
63
+ result = DataStore.open(
64
+ @user,
65
+ :data_set => 'field_ds_personal_details'
66
+ )
67
+ assert_equal(@name, result['first_name'])
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,102 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ensconce
4
+ class HashBuilderTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @words = %w{one two three}
8
+ @numbers = %w{1 2 3}
9
+ @hash_builder = HashBuilder.new(
10
+ :keys => @words,
11
+ :values => @numbers
12
+ )
13
+ end
14
+
15
+ def test_initiation
16
+ assert_equal @words, @hash_builder.keys
17
+ assert_equal @numbers, @hash_builder.values
18
+ end
19
+
20
+ def test_lack_of_keys
21
+ hash_builder = HashBuilder.new(:values => @numbers)
22
+ assert_raise RuntimeError do
23
+ hash_builder.hash
24
+ end
25
+ end
26
+
27
+ def test_lack_of_values
28
+ hash_builder = HashBuilder.new(:keys => @numbers)
29
+ assert_raise RuntimeError do
30
+ hash_builder.hash
31
+ end
32
+ end
33
+
34
+ def test_map
35
+ expected = {'one' => '1', 'two' => '2', 'three' => '3'}
36
+ assert_equal(expected, @hash_builder.hash)
37
+ end
38
+
39
+ def test_keys_mod
40
+ @hash_builder.keys_mod = lambda {|element| element.upcase}
41
+ expected = {'ONE' => '1', 'TWO' => '2', 'THREE' => '3'}
42
+ assert_equal(expected, @hash_builder.hash)
43
+ end
44
+
45
+ def test_keys_mod_with_invalid_input
46
+ @hash_builder.keys_mod = 'x'
47
+ assert_raise RuntimeError do
48
+ @hash_builder.hash
49
+ end
50
+ end
51
+
52
+ def test_values_mod
53
+ @hash_builder.values_mod = lambda {|element| (element.to_i * 2).to_s}
54
+ expected = {'one' => '2', 'two' => '4', 'three' => '6'}
55
+ assert_equal(expected, @hash_builder.hash)
56
+ end
57
+
58
+ # Test added to show how procs with returns in mods can cause unexpected results
59
+ def test_mod_with_proc
60
+ @hash_builder.values_mod = Proc.new {|element| return (element.to_i * 2).to_s}
61
+ map = @hash_builder.hash
62
+ flunk "Never gets here"
63
+ # because return in Proc stops process and returns value to test_mod_with_proc caller
64
+ end
65
+
66
+ # Demonstration that it is the return in the Proc that messes up the test.
67
+ # If you alter 'expected' in this test, the test will fail.
68
+ def test_mod_with_proc_and_no_return
69
+ @hash_builder.values_mod = Proc.new {|element| (element.to_i * 2).to_s}
70
+ expected = {'one' => '2', 'two' => '4', 'three' => '6'}
71
+ map = @hash_builder.hash
72
+ assert_equal(expected, map)
73
+ end
74
+
75
+ # Test with lambda shows a more predictable result
76
+ def test_mod_with_lambda
77
+ @hash_builder.values_mod = lambda {|element| return (element.to_i * 2).to_s}
78
+ expected = {'one' => '2', 'two' => '4', 'three' => '6'}
79
+ map = @hash_builder.hash
80
+ assert_equal(expected, map)
81
+ end
82
+
83
+ def test_mod_with_lambda_and_no_return
84
+ @hash_builder.values_mod = lambda {|element| (element.to_i * 2).to_s}
85
+ expected = {'one' => '2', 'two' => '4', 'three' => '6'}
86
+ map = @hash_builder.hash
87
+ assert_equal(expected, map)
88
+ end
89
+
90
+ def test_mods_on_initiation
91
+ hash_builder = HashBuilder.new(
92
+ :keys => @words,
93
+ :values => @numbers,
94
+ :keys_mod => lambda {|element| element.reverse},
95
+ :values_mod => Proc.new {|element| (element.to_i + 2).to_s}
96
+ )
97
+ expected = {'eno' => '3', 'owt' => '4', 'eerht' => '5'}
98
+ assert_equal(expected, hash_builder.hash)
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ensconce
4
+ class MydexKeyMapTest < Test::Unit::TestCase
5
+ def test_for
6
+ expected = {
7
+ "field_personal_fname"=>"first_name",
8
+ "field_personal_faname"=>"last_name",
9
+ "field_personal_gender"=>"gender",
10
+ "field_personal_maname"=>"maiden_name",
11
+ "field_personal_mname"=>"middle_name",
12
+ "field_personal_nickname"=>"nick_name",
13
+ "field_personal_suffix"=>"suffix",
14
+ "field_personal_title"=>"title"
15
+ }
16
+ map = MydexKeyMap.for('field_ds_personal_details')
17
+ assert_equal(expected, map)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ require_relative '../test_helper'
2
+
3
+ module Ensconce
4
+ class MangleTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @hash = {foo: {bar: 38, chew: 12}, this: 'that'}
8
+ end
9
+
10
+ def test_deep_merge
11
+ replacement = {foo: {bar: 21}}
12
+ expected = {foo: {bar: 21, chew: 12}, this: 'that'}
13
+ assert_equal(expected, Mangle.deep_merge(@hash, replacement))
14
+ end
15
+
16
+ def test_rekey
17
+ map = {
18
+ foo: :changed_foo,
19
+ this: :changed_this
20
+ }
21
+ expected = {changed_foo: {bar: 38, chew: 12}, changed_this: 'that'}
22
+ assert_equal(expected, Mangle.rekey(@hash, map))
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ user_1:
2
+ first_name: Bob
3
+ last_name: Bloggs
4
+ gender: Male
5
+
6
+ user_2:
7
+ first_name: Jane
8
+ last_name: Doe
9
+ gender: Female
@@ -0,0 +1,44 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sbx-api.mydex.org/api/pds/pds/93.json?api_key=rN31O75AWviNYezE2vWsMDP6kS88Zc5P&con_id=93-1545&data_set=field_ds_personal_details&dataset=field_ds_personal_details&key=LlPwdnq38tMtCPP7u60HjTYy35MxAVkf&source_type=connection
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.8.6
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - ! '*/*'
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Server:
22
+ - nginx
23
+ Date:
24
+ - Mon, 17 Mar 2014 14:20:21 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Transfer-Encoding:
28
+ - chunked
29
+ Connection:
30
+ - keep-alive
31
+ Expires:
32
+ - Sun, 19 Nov 1978 05:00:00 GMT
33
+ Last-Modified:
34
+ - Mon, 17 Mar 2014 14:20:21 +0000
35
+ Cache-Control:
36
+ - no-cache, must-revalidate, post-check=0, pre-check=0
37
+ Etag:
38
+ - ! '"1395066021"'
39
+ body:
40
+ encoding: US-ASCII
41
+ string: ! '{"field_ds_personal_details":{"instance_0":{"field_personal_faname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_fname":{"value":"Gillian","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_gender":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_maname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_mname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_nickname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_suffix":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_title":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}}}}}'
42
+ http_version:
43
+ recorded_at: Mon, 17 Mar 2014 14:20:27 GMT
44
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,85 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sbx-api.mydex.org/api/pds/pds/93.json?api_key=rN31O75AWviNYezE2vWsMDP6kS88Zc5P&con_id=93-1545&data_set=field_ds_personal_details&dataset=field_ds_personal_details&key=LlPwdnq38tMtCPP7u60HjTYy35MxAVkf&source_type=connection
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.8.6
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - ! '*/*'
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Server:
22
+ - nginx
23
+ Date:
24
+ - Mon, 17 Mar 2014 14:20:20 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Transfer-Encoding:
28
+ - chunked
29
+ Connection:
30
+ - keep-alive
31
+ Expires:
32
+ - Sun, 19 Nov 1978 05:00:00 GMT
33
+ Last-Modified:
34
+ - Mon, 17 Mar 2014 14:20:20 +0000
35
+ Cache-Control:
36
+ - no-cache, must-revalidate, post-check=0, pre-check=0
37
+ Etag:
38
+ - ! '"1395066020"'
39
+ body:
40
+ encoding: US-ASCII
41
+ string: ! '{"field_ds_personal_details":{"instance_0":{"field_personal_faname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_fname":{"value":"Trevor","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_gender":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_maname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_mname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_nickname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_suffix":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_title":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}}}}}'
42
+ http_version:
43
+ recorded_at: Mon, 17 Mar 2014 14:20:26 GMT
44
+ - request:
45
+ method: put
46
+ uri: https://sbx-api.mydex.org/api/pds/pds/93.json?api_key=rN31O75AWviNYezE2vWsMDP6kS88Zc5P&con_id=93-1545&data_set=field_ds_personal_details&key=LlPwdnq38tMtCPP7u60HjTYy35MxAVkf&source_type=connection
47
+ body:
48
+ encoding: UTF-8
49
+ string: ! '{"field_ds_personal_details":[{"field_personal_fname":"Gillian","field_personal_faname":"","field_personal_gender":"","field_personal_maname":"","field_personal_mname":"","field_personal_nickname":"","field_personal_suffix":"","field_personal_title":""}]}'
50
+ headers:
51
+ User-Agent:
52
+ - Faraday v0.8.6
53
+ Content-Type:
54
+ - application/json
55
+ Accept:
56
+ - ! '*/*'
57
+ response:
58
+ status:
59
+ code: 200
60
+ message: OK
61
+ headers:
62
+ Server:
63
+ - nginx
64
+ Date:
65
+ - Mon, 17 Mar 2014 14:20:21 GMT
66
+ Content-Type:
67
+ - application/json
68
+ Transfer-Encoding:
69
+ - chunked
70
+ Connection:
71
+ - keep-alive
72
+ Expires:
73
+ - Sun, 19 Nov 1978 05:00:00 GMT
74
+ Last-Modified:
75
+ - Mon, 17 Mar 2014 14:20:21 +0000
76
+ Cache-Control:
77
+ - no-cache, must-revalidate, post-check=0, pre-check=0
78
+ Etag:
79
+ - ! '"1395066021"'
80
+ body:
81
+ encoding: US-ASCII
82
+ string: ! '{"success":1,"data":{"field_ds_personal_details":[{"field_personal_fname":"Gillian","field_personal_faname":"","field_personal_gender":"","field_personal_maname":"","field_personal_mname":"","field_personal_nickname":"","field_personal_suffix":"","field_personal_title":""}]}}'
83
+ http_version:
84
+ recorded_at: Mon, 17 Mar 2014 14:20:26 GMT
85
+ recorded_with: VCR 2.4.0