data-anonymization 0.3.0 → 0.5.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/.gitignore +2 -1
- data/.rvmrc +1 -1
- data/.travis.yml +2 -0
- data/Gemfile +2 -0
- data/README.md +295 -258
- data/bin/datanon +57 -0
- data/data-anonymization.gemspec +2 -1
- data/examples/blacklist_dsl.rb +42 -0
- data/examples/mongodb_blacklist_dsl.rb +38 -0
- data/examples/mongodb_whitelist_dsl.rb +44 -0
- data/examples/whitelist_dsl.rb +63 -0
- data/lib/core/database.rb +21 -3
- data/lib/core/field.rb +5 -2
- data/lib/core/fields_missing_strategy.rb +30 -0
- data/lib/core/table_errors.rb +32 -0
- data/lib/data-anonymization.rb +11 -0
- data/lib/parallel/table.rb +8 -1
- data/lib/strategy/base.rb +35 -14
- data/lib/strategy/blacklist.rb +1 -1
- data/lib/strategy/field/anonymize_array.rb +28 -0
- data/lib/strategy/field/contact/random_address.rb +12 -0
- data/lib/strategy/field/contact/random_city.rb +12 -0
- data/lib/strategy/field/contact/random_phone_number.rb +4 -0
- data/lib/strategy/field/contact/random_province.rb +12 -0
- data/lib/strategy/field/contact/random_zipcode.rb +12 -0
- data/lib/strategy/field/datetime/anonymize_date.rb +15 -0
- data/lib/strategy/field/datetime/anonymize_datetime.rb +19 -0
- data/lib/strategy/field/datetime/anonymize_time.rb +19 -0
- data/lib/strategy/field/datetime/date_delta.rb +10 -0
- data/lib/strategy/field/datetime/date_time_delta.rb +9 -0
- data/lib/strategy/field/datetime/time_delta.rb +8 -0
- data/lib/strategy/field/default_anon.rb +4 -1
- data/lib/strategy/field/email/gmail_template.rb +8 -0
- data/lib/strategy/field/email/random_email.rb +7 -0
- data/lib/strategy/field/email/random_mailinator_email.rb +5 -0
- data/lib/strategy/field/fields.rb +4 -0
- data/lib/strategy/field/name/random_first_name.rb +10 -0
- data/lib/strategy/field/name/random_full_name.rb +10 -2
- data/lib/strategy/field/name/random_last_name.rb +9 -0
- data/lib/strategy/field/name/random_user_name.rb +5 -0
- data/lib/strategy/field/number/random_big_decimal_delta.rb +6 -0
- data/lib/strategy/field/number/random_float.rb +4 -0
- data/lib/strategy/field/number/random_float_delta.rb +6 -0
- data/lib/strategy/field/number/random_integer.rb +4 -0
- data/lib/strategy/field/number/random_integer_delta.rb +6 -0
- data/lib/strategy/field/string/formatted_string_numbers.rb +10 -6
- data/lib/strategy/field/string/lorem_ipsum.rb +9 -0
- data/lib/strategy/field/string/random_formatted_string.rb +39 -0
- data/lib/strategy/field/string/random_string.rb +6 -0
- data/lib/strategy/field/string/random_url.rb +7 -1
- data/lib/strategy/field/string/select_from_database.rb +7 -5
- data/lib/strategy/field/string/select_from_file.rb +7 -0
- data/lib/strategy/field/string/select_from_list.rb +8 -0
- data/lib/strategy/field/string/string_template.rb +11 -0
- data/lib/strategy/mongodb/anonymize_field.rb +44 -0
- data/lib/strategy/mongodb/blacklist.rb +29 -0
- data/lib/strategy/mongodb/whitelist.rb +62 -0
- data/lib/strategy/strategies.rb +10 -1
- data/lib/strategy/whitelist.rb +7 -2
- data/lib/thor/helpers/mongodb_dsl_generator.rb +66 -0
- data/lib/thor/helpers/rdbms_dsl_generator.rb +36 -0
- data/lib/thor/templates/mongodb_whitelist_template.erb +15 -0
- data/lib/thor/templates/whitelist_template.erb +21 -0
- data/lib/utils/database.rb +4 -0
- data/lib/utils/parallel_progress_bar.rb +24 -0
- data/lib/utils/progress_bar.rb +34 -22
- data/lib/utils/random_string.rb +3 -2
- data/lib/utils/random_string_chars_only.rb +3 -5
- data/lib/utils/template_helper.rb +44 -0
- data/lib/version.rb +1 -1
- data/spec/acceptance/mongodb_blacklist_spec.rb +75 -0
- data/spec/acceptance/mongodb_whitelist_spec.rb +107 -0
- data/spec/core/fields_missing_strategy_spec.rb +26 -0
- data/spec/strategy/field/name/random_first_name_spec.rb +1 -1
- data/spec/strategy/field/name/random_full_name_spec.rb +12 -7
- data/spec/strategy/field/name/random_last_name_spec.rb +1 -1
- data/spec/strategy/field/string/random_formatted_string_spec.rb +39 -0
- data/spec/strategy/field/string/select_from_file_spec.rb +21 -0
- data/spec/strategy/mongodb/anonymize_field_spec.rb +52 -0
- data/spec/utils/random_float_spec.rb +12 -0
- data/spec/utils/random_string_char_only_spec.rb +12 -0
- data/spec/utils/template_helper_spec.rb +14 -0
- metadata +56 -6
- data/blacklist_dsl.rb +0 -17
- data/blacklist_nosql_dsl.rb +0 -36
- data/whitelist_dsl.rb +0 -42
@@ -1,6 +1,12 @@
|
|
1
1
|
module DataAnon
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
|
+
|
5
|
+
# Shifts the current value randomly within given delta + and -. Default is 10.0
|
6
|
+
#
|
7
|
+
# !!!ruby
|
8
|
+
# anonymize('points').using FieldStrategy::RandomFloatDelta.new(2.5)
|
9
|
+
|
4
10
|
class RandomFloatDelta
|
5
11
|
|
6
12
|
def initialize delta = 10.0
|
@@ -1,6 +1,12 @@
|
|
1
1
|
module DataAnon
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
|
+
|
5
|
+
# Shifts the current value randomly within given delta + and -. Default is 10
|
6
|
+
#
|
7
|
+
# !!!ruby
|
8
|
+
# anonymize('Age').using FieldStrategy::RandomIntegerDelta.new(2)
|
9
|
+
|
4
10
|
class RandomIntegerDelta
|
5
11
|
|
6
12
|
def initialize delta = 10
|
@@ -2,21 +2,25 @@ module DataAnon
|
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
4
|
|
5
|
+
# Keeping the format same it changes each digit in the string with random digit.
|
6
|
+
#
|
7
|
+
# !!!ruby
|
8
|
+
# anonymize('CreditCardNumber').using FieldStrategy::FormattedStringNumber.new
|
5
9
|
|
6
10
|
class FormattedStringNumber
|
7
11
|
|
8
12
|
def anonymize field
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
13
|
+
@original_string = field.value
|
14
|
+
@anonymized_string = ""
|
15
|
+
@original_string.each_char do |char|
|
12
16
|
if /\d/.match(char).nil?
|
13
|
-
@
|
17
|
+
@anonymized_string += char
|
14
18
|
else
|
15
|
-
@
|
19
|
+
@anonymized_string += DataAnon::Utils::RandomInt.generate(0,9).to_s
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
19
|
-
@
|
23
|
+
@anonymized_string
|
20
24
|
end
|
21
25
|
|
22
26
|
end
|
@@ -2,6 +2,15 @@ module DataAnon
|
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
4
|
|
5
|
+
# Default anonymization strategy for `string` content. Uses default 'Lorem ipsum...' text or text supplied in strategy to generate same length string.
|
6
|
+
# !!!ruby
|
7
|
+
# anonymize('UserName').using FieldStrategy::LoremIpsum.new
|
8
|
+
#
|
9
|
+
# !!!ruby
|
10
|
+
# anonymize('UserName').using FieldStrategy::LoremIpsum.new("very large string....")
|
11
|
+
#
|
12
|
+
# !!!ruby
|
13
|
+
# anonymize('UserName').using FieldStrategy::LoremIpsum.new(File.read('my_file.txt'))
|
5
14
|
|
6
15
|
class LoremIpsum
|
7
16
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module DataAnon
|
2
|
+
module Strategy
|
3
|
+
module Field
|
4
|
+
|
5
|
+
# Keeping the format same it changes each digit with random digit, character with character preserving the case.
|
6
|
+
#
|
7
|
+
# !!!ruby
|
8
|
+
# anonymize('PhoneNumber').using FieldStrategy::RandomFormattedString.new
|
9
|
+
# anonymize('Email').using FieldStrategy::RandomFormattedString.new
|
10
|
+
|
11
|
+
class RandomFormattedString
|
12
|
+
|
13
|
+
SMALL_CHARS = "abcdefghjkmnpqrstuvwxyz"
|
14
|
+
CAPS_CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZ"
|
15
|
+
|
16
|
+
def anonymize field
|
17
|
+
@original_string = field.value
|
18
|
+
@anonymized_string = ""
|
19
|
+
@original_string.each_char do |char|
|
20
|
+
if /\d/.match(char)
|
21
|
+
@anonymized_string += DataAnon::Utils::RandomInt.generate(0, 9).to_s
|
22
|
+
elsif /[a-z]/.match(char)
|
23
|
+
@anonymized_string += SMALL_CHARS[rand(SMALL_CHARS.length)]
|
24
|
+
elsif /[A-Z]/.match(char)
|
25
|
+
@anonymized_string += CAPS_CHARS[rand(CAPS_CHARS.length)]
|
26
|
+
else
|
27
|
+
@anonymized_string += char
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@anonymized_string
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,7 +1,13 @@
|
|
1
1
|
module DataAnon
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
|
-
|
4
|
+
|
5
|
+
# Generates a randomized URL while maintaining the structure of the original url
|
6
|
+
#
|
7
|
+
# !!!ruby
|
8
|
+
# anonymize('fb_profile').using FieldStrategy::RandomURL.new
|
9
|
+
|
10
|
+
class RandomUrl
|
5
11
|
|
6
12
|
def anonymize field
|
7
13
|
|
@@ -2,7 +2,13 @@ module DataAnon
|
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
4
|
|
5
|
-
|
5
|
+
# Similar to SelectFromList with difference is the list of values are collected from the database table using distinct column query.
|
6
|
+
#
|
7
|
+
# !!!ruby
|
8
|
+
# # values are collected using `select distinct state from customers` query
|
9
|
+
# anonymize('State').using FieldStrategy::SelectFromDatabase.new('customers','state')
|
10
|
+
|
11
|
+
class SelectFromDatabase < SelectFromFile
|
6
12
|
include Utils::Logging
|
7
13
|
|
8
14
|
def initialize table_name, field_name, connection_spec
|
@@ -13,10 +19,6 @@ module DataAnon
|
|
13
19
|
|
14
20
|
end
|
15
21
|
|
16
|
-
def anonymize field
|
17
|
-
@values[DataAnon::Utils::RandomInt.generate(0,(@values.length - 1))]
|
18
|
-
end
|
19
|
-
|
20
22
|
end
|
21
23
|
|
22
24
|
|
@@ -2,6 +2,12 @@ module DataAnon
|
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
4
|
|
5
|
+
# Similar to SelectFromList only difference is the list of values are picked up from file. Classical usage is like states field anonymization.
|
6
|
+
#
|
7
|
+
# !!!ruby
|
8
|
+
# anonymize('State').using FieldStrategy::SelectFromFile.new('states.txt')
|
9
|
+
#
|
10
|
+
|
5
11
|
class SelectFromFile
|
6
12
|
|
7
13
|
def initialize file_path
|
@@ -9,6 +15,7 @@ module DataAnon
|
|
9
15
|
end
|
10
16
|
|
11
17
|
def anonymize field
|
18
|
+
return @values.sample(field.value.length) if field.value.kind_of? Array
|
12
19
|
@values.sample
|
13
20
|
end
|
14
21
|
|
@@ -2,6 +2,14 @@ module DataAnon
|
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
4
|
|
5
|
+
# Select randomly one of the values specified.
|
6
|
+
#
|
7
|
+
# !!!ruby
|
8
|
+
# anonymize('State').using FieldStrategy::SelectFromList.new(['New York','Georgia',...])
|
9
|
+
#
|
10
|
+
# !!!ruby
|
11
|
+
# anonymize('NameTitle').using FieldStrategy::SelectFromList.new(['Mr','Mrs','Dr',...])
|
12
|
+
#
|
5
13
|
|
6
14
|
class SelectFromList < SelectFromFile
|
7
15
|
|
@@ -2,6 +2,17 @@ module DataAnon
|
|
2
2
|
module Strategy
|
3
3
|
module Field
|
4
4
|
|
5
|
+
# Simple string evaluation within [DataAnon::Core::Field](#dataanon-core-field) context. Can be used for email, username anonymization.
|
6
|
+
# Make sure to put the string in 'single quote' else it will get evaluated inline.
|
7
|
+
#
|
8
|
+
# !!!ruby
|
9
|
+
# anonymize('UserName').using FieldStrategy::StringTemplate.new('user#{row_number}')
|
10
|
+
#
|
11
|
+
# !!!ruby
|
12
|
+
# anonymize('Email').using FieldStrategy::StringTemplate.new('valid.address+#{row_number}@gmail.com')
|
13
|
+
#
|
14
|
+
# !!!ruby
|
15
|
+
# anonymize('Email').using FieldStrategy::StringTemplate.new('useremail#{row_number}@mailinator.com')
|
5
16
|
|
6
17
|
class StringTemplate
|
7
18
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module DataAnon
|
2
|
+
module Strategy
|
3
|
+
module MongoDB
|
4
|
+
class AnonymizeField
|
5
|
+
|
6
|
+
def initialize field, field_strategy, anonymization_strategy
|
7
|
+
@field = field
|
8
|
+
@field_strategy = field_strategy
|
9
|
+
@anonymization_strategy = anonymization_strategy
|
10
|
+
end
|
11
|
+
|
12
|
+
def anonymize
|
13
|
+
if sub_document?
|
14
|
+
@anonymization_strategy.anonymize_document(@field.value, @field.row_number, @field_strategy)
|
15
|
+
elsif sub_documents?
|
16
|
+
anonymize_sub_documents
|
17
|
+
else
|
18
|
+
anonymize_field
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def anonymize_sub_documents
|
23
|
+
@field.value.collect { |value| @anonymization_strategy.anonymize_document(value, @field.row_number, @field_strategy) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def anonymize_field
|
27
|
+
@field_strategy = @field_strategy || @anonymization_strategy.default_strategy(@field.name)
|
28
|
+
raise "Improper fields strategy defined for '#{@field.name}' within document \n #{@field.ar_record}" unless @field_strategy.respond_to?(:anonymize)
|
29
|
+
@field_strategy.anonymize(@field)
|
30
|
+
end
|
31
|
+
|
32
|
+
def sub_documents?
|
33
|
+
@field.value.kind_of?(Array) && @field.value[0].kind_of?(Hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def sub_document?
|
37
|
+
@field.value.kind_of? Hash
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DataAnon
|
2
|
+
module Strategy
|
3
|
+
module MongoDB
|
4
|
+
class Blacklist < DataAnon::Strategy::MongoDB::Whitelist
|
5
|
+
|
6
|
+
def self.whitelist?
|
7
|
+
false
|
8
|
+
end
|
9
|
+
|
10
|
+
def process_record index, document
|
11
|
+
source_collection.save anonymize_document(document, index, @fields)
|
12
|
+
end
|
13
|
+
|
14
|
+
def anonymize_document document, index, field_strategies = {}
|
15
|
+
field_strategies.each do |field_name, field_strategy|
|
16
|
+
field_value = document[field_name]
|
17
|
+
unless field_value.nil?
|
18
|
+
field = DataAnon::Core::Field.new(field_name, field_value, index, document, @name)
|
19
|
+
document[field.name] = AnonymizeField.new(field, field_strategy, self).anonymize
|
20
|
+
end
|
21
|
+
end
|
22
|
+
document
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
|
3
|
+
class Mongo::Collection
|
4
|
+
alias :all :find
|
5
|
+
end
|
6
|
+
|
7
|
+
module DataAnon
|
8
|
+
module Strategy
|
9
|
+
module MongoDB
|
10
|
+
class Whitelist < DataAnon::Strategy::Base
|
11
|
+
|
12
|
+
def self.whitelist?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def collection field, &block
|
17
|
+
whitelist = self.class.new @source_database, @destination_database, @name, @user_strategies
|
18
|
+
whitelist.process_fields &block
|
19
|
+
@fields[field] = whitelist.fields
|
20
|
+
end
|
21
|
+
|
22
|
+
alias :document :collection
|
23
|
+
|
24
|
+
def mongo_collection(database)
|
25
|
+
options = database[:options] || {}
|
26
|
+
Mongo::Connection.from_uri(database[:mongodb_uri], options)[database[:database]][@name]
|
27
|
+
end
|
28
|
+
|
29
|
+
def dest_collection
|
30
|
+
database = @destination_database
|
31
|
+
@dest_collection ||= mongo_collection(database)
|
32
|
+
end
|
33
|
+
|
34
|
+
def source_collection
|
35
|
+
@source_collection ||= mongo_collection(@source_database)
|
36
|
+
end
|
37
|
+
|
38
|
+
alias :source_table :source_collection
|
39
|
+
alias :dest_table :dest_collection
|
40
|
+
|
41
|
+
def process_record index, document
|
42
|
+
dest_collection.insert anonymize_document(document, index, @fields)
|
43
|
+
end
|
44
|
+
|
45
|
+
def anonymize_document document, index, field_strategies = {}
|
46
|
+
anonymized_document = {}
|
47
|
+
document.each do |field_name, field_value|
|
48
|
+
field_strategy = field_strategies[field_name.downcase] if field_strategies.kind_of?(Hash)
|
49
|
+
unless field_value.nil?
|
50
|
+
field = DataAnon::Core::Field.new(field_name, field_value, index, document, @name)
|
51
|
+
anonymized_document[field.name] = AnonymizeField.new(field, field_strategy, self).anonymize
|
52
|
+
end
|
53
|
+
end
|
54
|
+
anonymized_document
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/strategy/strategies.rb
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
require 'strategy/base'
|
2
2
|
require 'strategy/whitelist'
|
3
3
|
require 'strategy/blacklist'
|
4
|
-
require 'strategy/field/fields'
|
4
|
+
require 'strategy/field/fields'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'mongo'
|
8
|
+
require 'strategy/mongodb/anonymize_field'
|
9
|
+
require 'strategy/mongodb/whitelist'
|
10
|
+
require 'strategy/mongodb/blacklist'
|
11
|
+
rescue LoadError
|
12
|
+
"Ignoring the mongodb specific libraries if monog driver is not specified in gem"
|
13
|
+
end
|
data/lib/strategy/whitelist.rb
CHANGED
@@ -2,12 +2,16 @@ module DataAnon
|
|
2
2
|
module Strategy
|
3
3
|
class Whitelist < DataAnon::Strategy::Base
|
4
4
|
|
5
|
+
def self.whitelist?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
5
9
|
def process_record(index, record)
|
6
10
|
dest_record_map = {}
|
7
11
|
record.attributes.each do |field_name, field_value|
|
8
12
|
unless field_value.nil? || is_primary_key?(field_name)
|
9
|
-
field = DataAnon::Core::Field.new(field_name, field_value, index, record)
|
10
|
-
field_strategy = @fields[field_name.downcase] ||
|
13
|
+
field = DataAnon::Core::Field.new(field_name, field_value, index, record, @name)
|
14
|
+
field_strategy = @fields[field_name.downcase] || default_strategy(field_name)
|
11
15
|
dest_record_map[field_name] = field_strategy.anonymize(field)
|
12
16
|
end
|
13
17
|
end
|
@@ -18,6 +22,7 @@ module DataAnon
|
|
18
22
|
dest_record.save!
|
19
23
|
end
|
20
24
|
|
25
|
+
|
21
26
|
end
|
22
27
|
end
|
23
28
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module DataAnon
|
5
|
+
module ThorHelpers
|
6
|
+
class MongoDBDSLGenerator
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.dirname(__FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(configuration_hash, whitelist_patterns)
|
13
|
+
@mongodb_uri = DataAnon::Utils::TemplateHelper.mongo_uri(configuration_hash)
|
14
|
+
@whitelist_patterns = whitelist_patterns || [/^_/,/_at$/,/_id$/,/_type$/]
|
15
|
+
@configuration_hash = configuration_hash
|
16
|
+
@output = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate
|
20
|
+
|
21
|
+
db = Mongo::Connection.from_uri(@mongodb_uri)[@configuration_hash[:database]]
|
22
|
+
collections = db.collections
|
23
|
+
collections.each do |collection|
|
24
|
+
unless collection.name.start_with?('system.')
|
25
|
+
depth = 2
|
26
|
+
@output << "\tcollection '#{collection.name}' do"
|
27
|
+
document = collection.find_one
|
28
|
+
process_document(depth, document)
|
29
|
+
@output << "\tend\n"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
erb = ERB.new( File.new(RDBMSDSLGenerator.source_root + "/../templates/mongodb_whitelist_template.erb").read, nil, '-')
|
34
|
+
File.open('mongodb_whitelist_generated.rb', 'w') do |f|
|
35
|
+
f.write erb.result(binding)
|
36
|
+
f.close
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_document(depth, document)
|
42
|
+
return if document.nil?
|
43
|
+
document.each do |key, value|
|
44
|
+
@output << ("\t"*depth)
|
45
|
+
if value.kind_of?(Hash)
|
46
|
+
end_statement = @output[-1]+"end"
|
47
|
+
@output[-1] << "document '#{key}' do"
|
48
|
+
process_document depth+1, value
|
49
|
+
@output << end_statement
|
50
|
+
elsif value.kind_of?(Array) && value[0].kind_of?(Hash)
|
51
|
+
end_statement = @output[-1]+"end"
|
52
|
+
@output[-1] << "collection '#{key}' do"
|
53
|
+
process_document depth+1, value[0]
|
54
|
+
@output << end_statement
|
55
|
+
elsif @whitelist_patterns.collect { |pattern| key.match(pattern) }.compact.length > 0
|
56
|
+
@output[-1] << "whitelist '#{key}'"
|
57
|
+
elsif
|
58
|
+
@output[-1] << "anonymize '#{key}'"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|