fathom 0.3.7 → 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.
Files changed (134) hide show
  1. data/.autotest +7 -5
  2. data/.document +2 -2
  3. data/Gemfile +9 -10
  4. data/{LICENSE → LICENSE.txt} +1 -1
  5. data/README.md +29 -90
  6. data/Rakefile +34 -32
  7. data/VERSION +1 -1
  8. data/fathom.gemspec +105 -0
  9. data/features/fathom.feature +26 -0
  10. data/features/step_definitions/fathom_steps.rb +23 -0
  11. data/features/support/env.rb +13 -0
  12. data/lib/ext/array.rb +6 -2
  13. data/lib/ext/string.rb +86 -7
  14. data/lib/fathom.rb +51 -88
  15. data/lib/fathom/behaviors/attribute_system.rb +91 -0
  16. data/lib/fathom/behaviors/context_behavior.rb +28 -0
  17. data/lib/fathom/behaviors/plugins.rb +16 -0
  18. data/lib/fathom/contexts/network_population.rb +47 -0
  19. data/lib/fathom/contexts/network_traversal.rb +4 -0
  20. data/lib/fathom/data/adjacency_matrix.rb +27 -0
  21. data/lib/fathom/data/definition.rb +22 -0
  22. data/lib/fathom/data/edge.rb +58 -0
  23. data/lib/fathom/data/network.rb +35 -0
  24. data/lib/fathom/data/outcome.rb +30 -0
  25. data/lib/fathom/data/property.rb +31 -0
  26. data/lib/fathom/data/variable.rb +59 -0
  27. data/lib/fathom/roles/general_graph_tools.rb +87 -0
  28. data/lib/fathom/roles/network_builder.rb +61 -0
  29. data/spec/fathom/behaviors/attribute_system_spec.rb +141 -0
  30. data/spec/fathom/behaviors/context_behavior_spec.rb +15 -0
  31. data/spec/fathom/behaviors/plugins_spec.rb +80 -0
  32. data/spec/fathom/contexts/network_population_spec.rb +55 -0
  33. data/spec/fathom/contexts/network_traversal_spec.rb +11 -0
  34. data/spec/fathom/data/adjacency_matrix_spec.rb +42 -0
  35. data/spec/fathom/data/definition_spec.rb +19 -0
  36. data/spec/fathom/data/edge_spec.rb +77 -0
  37. data/spec/fathom/data/network_spec.rb +72 -0
  38. data/spec/fathom/data/outcome_spec.rb +17 -0
  39. data/spec/fathom/data/property_spec.rb +17 -0
  40. data/spec/fathom/data/variable_spec.rb +101 -0
  41. data/spec/fathom/ext/array_spec.rb +17 -0
  42. data/spec/fathom/ext/string_spec.rb +90 -0
  43. data/spec/fathom/roles/general_graph_tools_spec.rb +95 -0
  44. data/spec/fathom/roles/network_builder_spec.rb +90 -0
  45. data/spec/fathom_spec.rb +28 -49
  46. data/spec/spec_helper.rb +7 -11
  47. data/spec/support/context_behavior.rb +14 -0
  48. data/spec/support/custom_matchers.rb +12 -0
  49. data/spec/support/files.rb +8 -0
  50. data/spec/support/network.yml +42 -0
  51. metadata +133 -174
  52. data/.bundle/config +0 -2
  53. data/.gitignore +0 -6
  54. data/Gemfile.lock +0 -42
  55. data/TODO.md +0 -127
  56. data/autotest/discover.rb +0 -1
  57. data/lib/ext/faster_csv.rb +0 -1
  58. data/lib/ext/open_struct.rb +0 -17
  59. data/lib/fathom/agent.rb +0 -48
  60. data/lib/fathom/agent/agent_cluster.rb +0 -23
  61. data/lib/fathom/agent/properties.rb +0 -48
  62. data/lib/fathom/archive/causal_graph.rb +0 -12
  63. data/lib/fathom/archive/concept.rb +0 -83
  64. data/lib/fathom/archive/conditional_probability_matrix.rb +0 -119
  65. data/lib/fathom/archive/inverter.rb +0 -20
  66. data/lib/fathom/archive/n2.rb +0 -198
  67. data/lib/fathom/archive/n3.rb +0 -119
  68. data/lib/fathom/archive/node.rb +0 -97
  69. data/lib/fathom/archive/noodle.rb +0 -136
  70. data/lib/fathom/archive/scratch.rb +0 -45
  71. data/lib/fathom/distributions.rb +0 -8
  72. data/lib/fathom/distributions/discrete_gaussian.rb +0 -44
  73. data/lib/fathom/distributions/discrete_uniform.rb +0 -25
  74. data/lib/fathom/distributions/gaussian.rb +0 -46
  75. data/lib/fathom/distributions/uniform.rb +0 -35
  76. data/lib/fathom/import.rb +0 -85
  77. data/lib/fathom/import/csv_import.rb +0 -59
  78. data/lib/fathom/import/import_node.rb +0 -17
  79. data/lib/fathom/import/yaml_import.rb +0 -74
  80. data/lib/fathom/knowledge_base.rb +0 -46
  81. data/lib/fathom/knowledge_base/search.rb +0 -19
  82. data/lib/fathom/monte_carlo_set.rb +0 -152
  83. data/lib/fathom/node.rb +0 -139
  84. data/lib/fathom/node/belief_node.rb +0 -121
  85. data/lib/fathom/node/cpm_node.rb +0 -100
  86. data/lib/fathom/node/data_collection.rb +0 -97
  87. data/lib/fathom/node/data_node.rb +0 -22
  88. data/lib/fathom/node/decision.rb +0 -11
  89. data/lib/fathom/node/discrete_node.rb +0 -41
  90. data/lib/fathom/node/fact.rb +0 -24
  91. data/lib/fathom/node/mc_node.rb +0 -70
  92. data/lib/fathom/node/node_extensions/enforced_name.rb +0 -12
  93. data/lib/fathom/node/node_extensions/numeric_methods.rb +0 -68
  94. data/lib/fathom/node/plausible_range.rb +0 -98
  95. data/lib/fathom/simulation.rb +0 -59
  96. data/lib/fathom/simulation/tick_methods.rb +0 -25
  97. data/lib/fathom/simulation/tick_simulation.rb +0 -12
  98. data/lib/fathom/value_description.rb +0 -79
  99. data/lib/options_hash.rb +0 -186
  100. data/spec/ext/array_spec.rb +0 -10
  101. data/spec/ext/faster_csv_spec.rb +0 -10
  102. data/spec/ext/open_struct_spec.rb +0 -20
  103. data/spec/ext/string_spec.rb +0 -7
  104. data/spec/fathom/agent/agent_cluster_spec.rb +0 -17
  105. data/spec/fathom/agent_spec.rb +0 -51
  106. data/spec/fathom/distributions/discrete_gaussian_spec.rb +0 -64
  107. data/spec/fathom/distributions/discrete_uniform_spec.rb +0 -0
  108. data/spec/fathom/distributions/gaussian_spec.rb +0 -64
  109. data/spec/fathom/distributions/uniform_spec.rb +0 -0
  110. data/spec/fathom/import/csv_import_spec.rb +0 -52
  111. data/spec/fathom/import/import_node_spec.rb +0 -10
  112. data/spec/fathom/import/yaml_import_spec.rb +0 -73
  113. data/spec/fathom/import_spec.rb +0 -36
  114. data/spec/fathom/knowledge_base_spec.rb +0 -20
  115. data/spec/fathom/monte_carlo_set_spec.rb +0 -149
  116. data/spec/fathom/node/belief_node_spec.rb +0 -180
  117. data/spec/fathom/node/cpm_node_spec.rb +0 -144
  118. data/spec/fathom/node/data_collection_spec.rb +0 -26
  119. data/spec/fathom/node/data_node_spec.rb +0 -102
  120. data/spec/fathom/node/decision_spec.rb +0 -15
  121. data/spec/fathom/node/discrete_node_spec.rb +0 -56
  122. data/spec/fathom/node/fact_spec.rb +0 -33
  123. data/spec/fathom/node/mc_node_spec.rb +0 -66
  124. data/spec/fathom/node/node_extensions/enforced_name_spec.rb +0 -15
  125. data/spec/fathom/node/node_extensions/numeric_methods_spec.rb +0 -124
  126. data/spec/fathom/node/plausible_range_spec.rb +0 -151
  127. data/spec/fathom/node_spec.rb +0 -172
  128. data/spec/fathom/simulation/tick_simulation_spec.rb +0 -32
  129. data/spec/fathom/simulation_spec.rb +0 -24
  130. data/spec/fathom/value_description_spec.rb +0 -70
  131. data/spec/support/demo.yml +0 -17
  132. data/spec/support/demo_agent.rb +0 -8
  133. data/spec/support/dummy_numeric_node.rb +0 -8
  134. data/spec/support/fact.yml +0 -11
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup(:default, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
11
+ require 'fathom'
12
+
13
+ require 'rspec/expectations'
@@ -1,5 +1,9 @@
1
1
  class Array
2
- def rand
3
- self[Kernel.rand(self.length)]
2
+ def invert(&block)
3
+ h = {}
4
+ self.each_with_index do |x, i|
5
+ h[x] = block ? yield(x, i) : i
6
+ end
7
+ h
4
8
  end
5
9
  end
@@ -1,8 +1,39 @@
1
- # From ActiveSupport
2
- class String
1
+ module Inflector
2
+ extend self
3
+
4
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
5
+ if first_letter_in_uppercase
6
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
7
+ else
8
+ lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
9
+ end
10
+ end
11
+
12
+ def underscore(camel_cased_word)
13
+ word = camel_cased_word.to_s.dup
14
+ word.gsub!(/::/, '/')
15
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
16
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
17
+ word.tr!("-", "_")
18
+ word.downcase!
19
+ word
20
+ end
21
+
22
+ def dasherize(underscored_word)
23
+ underscored_word.gsub(/_/, '-')
24
+ end
25
+
26
+ def demodulize(class_name_in_module)
27
+ class_name_in_module.to_s.gsub(/^.*::/, '')
28
+ end
29
+
30
+ def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
31
+ underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
32
+ end
33
+
3
34
  if Module.method(:const_get).arity == 1
4
- def constantize
5
- names = self.split('::')
35
+ def constantize(camel_cased_word)
36
+ names = camel_cased_word.split('::')
6
37
  names.shift if names.empty? || names.first.empty?
7
38
 
8
39
  constant = Object
@@ -12,8 +43,8 @@ class String
12
43
  constant
13
44
  end
14
45
  else
15
- def constantize #:nodoc:
16
- names = self.split('::')
46
+ def constantize(camel_cased_word) #:nodoc:
47
+ names = camel_cased_word.split('::')
17
48
  names.shift if names.empty? || names.first.empty?
18
49
 
19
50
  constant = Object
@@ -23,5 +54,53 @@ class String
23
54
  constant
24
55
  end
25
56
  end
57
+
58
+ def ordinalize(number)
59
+ if (11..13).include?(number.to_i % 100)
60
+ "#{number}th"
61
+ else
62
+ case number.to_i % 10
63
+ when 1; "#{number}st"
64
+ when 2; "#{number}nd"
65
+ when 3; "#{number}rd"
66
+ else "#{number}th"
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ class String
73
+ def constantize
74
+ Inflector.constantize(self)
75
+ end
76
+
77
+ def camelize(first_letter_in_uppercase = true)
78
+ Inflector.camelize(self, first_letter_in_uppercase)
79
+ end
80
+
81
+ def underscore
82
+ Inflector.underscore(self)
83
+ end
84
+
85
+ def dasherize
86
+ Inflector.dasherize(self)
87
+ end
88
+
89
+ def demodulize
90
+ Inflector.demodulize(self)
91
+ end
92
+
93
+ def foreign_key(separate_class_name_and_id_with_underscore = true)
94
+ Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
95
+ end
96
+
97
+ def ordinalize
98
+ Inflector.ordinalize(self)
99
+ end
100
+
101
+ def wrap(col=80)
102
+ # http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
103
+ gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/, "\\1\\3\n")
104
+ end
26
105
 
27
- end
106
+ end
@@ -1,103 +1,66 @@
1
1
  # ================
2
2
  # = Dependencies =
3
3
  # ================
4
+ Dir.glob("#{File.dirname(__FILE__)}/ext/*.rb").each { |file| require file}
4
5
 
5
- # Make decoupling easier with an informed LoadPath
6
- $:.unshift(File.dirname(__FILE__))
7
- $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), 'fathom')))
8
-
9
- require 'rubygems'
10
-
11
- require "gsl"
12
- require 'options_hash'
13
-
14
- require 'ext/open_struct'
15
- require 'ext/array'
16
- require 'ext/string'
6
+ require 'uuid'
17
7
 
18
8
  module Fathom
19
- lib = File.expand_path(File.dirname(__FILE__))
20
- $LOAD_PATH.unshift(lib)
21
9
 
22
- # Autoload classes and modules so that we only load as much of the library as we're using.
23
- # This allows us to have a fairly large library without taking up a lot of memory unless we need it.
24
- # autoload :Node, "node"
25
- # autoload :BeliefNode, "node/belief_node"
26
- # autoload :DataCollection, "node/data_collection"
27
- # autoload :DataNode, "node/data_node"
28
- # autoload :DiscreteNode, "node/discrete_node"
29
- # autoload :MCNode, "node/mc_node"
30
- # autoload :PlausibleRange, "node/plausible_range"
31
- # autoload :Fact, "node/fact"
32
- # autoload :Decision, "node/decision"
33
- # autoload :CPMNode, 'node/cpm_node'
34
- #
35
- # autoload :ValueDescription, "value_description"
36
- # autoload :MonteCarloSet, "monte_carlo_set"
37
- # autoload :KnowledgeBase, "knowledge_base"
38
- #
39
- # autoload :Import, "import"
40
- # autoload :ImportNode, "import/import_node"
41
- # autoload :YAMLImport, 'import/yaml_import'
42
- # autoload :CSVImport, 'import/csv_import'
43
- # # autoload :RDFImport, 'import/rdf_import'
44
- # # autoload :SQLiteImport, 'import/sqlite_import'
45
- #
46
- # autoload :Simulation, 'simulation'
47
- # autoload :TickMethods, 'simulation/tick_methods'
48
- # autoload :TickSimulation, 'simulation/tick_simulation'
49
- #
50
- # autoload :Agent, 'agent'
51
- # autoload :Properties, 'agent/properties'
52
- # autoload :AgentCluster, 'agent/agent_cluster'
53
- #
54
- # autoload :EnforcedName, 'node/node_extensions/enforced_name'
55
- # autoload :NumericMethods, 'node/node_extensions/numeric_methods'
56
-
57
- require 'distributions'
58
- module Distributions
59
- autoload :Gaussian, 'distributions/gaussian'
60
- autoload :Uniform, 'distributions/uniform'
61
- autoload :DiscreteGaussian, 'distributions/discrete_gaussian'
62
- autoload :DiscreteUniform, 'distributions/discrete_uniform'
10
+ class Config
11
+ attr_writer :storage
12
+ def storage
13
+ @storage ||= Hash
14
+ end
63
15
  end
64
-
65
- def knowledge_base
66
- @knowledge_base ||= KnowledgeBase.new
16
+
17
+ # =================
18
+ # = Configuration =
19
+ # =================
20
+ class << self
21
+ # A reset-able configuration that provides access to other services (pod storage, say)
22
+ def config
23
+ @config ||= Config.new
24
+ end
25
+
26
+ # The reset on the configuration
27
+ def reset_config!
28
+ @config = Config.new
29
+ end
67
30
  end
68
- alias :kb :knowledge_base
31
+
69
32
  end
70
33
 
71
- # Temporary
72
- # include Fathom
73
-
74
- Fathom.autoload :Node, "node"
75
- Fathom.autoload :BeliefNode, "node/belief_node"
76
- Fathom.autoload :DataCollection, "node/data_collection"
77
- Fathom.autoload :DataNode, "node/data_node"
78
- Fathom.autoload :DiscreteNode, "node/discrete_node"
79
- Fathom.autoload :MCNode, "node/mc_node"
80
- Fathom.autoload :PlausibleRange, "node/plausible_range"
81
- Fathom.autoload :Fact, "node/fact"
82
- Fathom.autoload :Decision, "node/decision"
83
- Fathom.autoload :CPMNode, 'node/cpm_node'
84
-
85
- Fathom.autoload :ValueDescription, "value_description"
86
- Fathom.autoload :MonteCarloSet, "monte_carlo_set"
87
- Fathom.autoload :KnowledgeBase, "knowledge_base"
34
+ def path(path)
35
+ File.expand_path("../fathom/#{path}", __FILE__)
36
+ end
88
37
 
89
- Fathom.autoload :Import, "import"
90
- Fathom.autoload :ImportNode, "import/import_node"
91
- Fathom.autoload :YAMLImport, 'import/yaml_import'
92
- Fathom.autoload :CSVImport, 'import/csv_import'
38
+ # =============
39
+ # = Behaviors =
40
+ # =============
41
+ Fathom.autoload :AttributeSystem, path('behaviors/attribute_system')
42
+ Fathom.autoload :ContextBehavior, path('behaviors/context_behavior')
43
+ Fathom.autoload :Plugins, path('behaviors/plugins')
93
44
 
94
- Fathom.autoload :Simulation, 'simulation'
95
- Fathom.autoload :TickMethods, 'simulation/tick_methods'
96
- Fathom.autoload :TickSimulation, 'simulation/tick_simulation'
45
+ # ===============
46
+ # = Data Models =
47
+ # ===============
48
+ Fathom.autoload :AdjacencyMatrix, path('data/adjacency_matrix')
49
+ Fathom.autoload :Definition, path('data/definition')
50
+ Fathom.autoload :Edge, path('data/edge')
51
+ Fathom.autoload :Network, path('data/network')
52
+ Fathom.autoload :Outcome, path('data/outcome')
53
+ Fathom.autoload :Property, path('data/property')
54
+ Fathom.autoload :Variable, path('data/variable')
97
55
 
98
- Fathom.autoload :Agent, 'agent'
99
- Fathom.autoload :Properties, 'agent/properties'
100
- Fathom.autoload :AgentCluster, 'agent/agent_cluster'
56
+ # ============
57
+ # = Contexts =
58
+ # ============
59
+ Fathom.autoload :NetworkPopulation, path('contexts/network_population')
60
+ Fathom.autoload :NetworkTraversal, path('contexts/network_traversal')
101
61
 
102
- Fathom.autoload :EnforcedName, 'node/node_extensions/enforced_name'
103
- Fathom.autoload :NumericMethods, 'node/node_extensions/numeric_methods'
62
+ # =========
63
+ # = Roles =
64
+ # =========
65
+ Fathom.autoload :NetworkBuilder, path('roles/network_builder')
66
+ Fathom.autoload :GeneralGraphTools, path('roles/general_graph_tools')
@@ -0,0 +1,91 @@
1
+ module Fathom
2
+
3
+ # This is a simple way to use thin Ruby classes to only store data values for attributes.
4
+ # In this way, we can have data models that can have various roles injected into them at
5
+ # runtime and perform fairly well. We can also have other kinds of data models mixed into
6
+ # Fathom, such as an ActiveRecord or DataMapper model, and we can just ignore this system
7
+ # altogether.
8
+ #
9
+ # It is important that it is easy to set an attributes_proxy. Other Fathom gems
10
+ # (say fm-redis, if I were to write that gem) could override the AttributeSystem default
11
+ # attributes to store data in a Redis data store directly. This is what the set_attributes_proxy
12
+ # is designed to do here.
13
+ #
14
+ # Example Usage:
15
+ # require 'memcache'
16
+ # CACHE = MemCache.new 'localhost:11211', :namespace => 'my_project'
17
+ # CACHE[1] = {:name => 'special'}
18
+ #
19
+ # class MyClass
20
+ # extend Fathom::Plugins
21
+ # plugin Fathom::AttributeSystem
22
+ #
23
+ # attribute :name
24
+ # attribute :value, 1
25
+ #
26
+ # def initialize(attrs={})
27
+ # @attributes = attrs
28
+ # end
29
+ # end
30
+ #
31
+ # obj = MyClass.new(CACHE[1])
32
+ # obj.name # => special
33
+ # obj.value # => 1
34
+ module AttributeSystem
35
+
36
+ module ClassMethods
37
+
38
+ # Define an attribute, or property of this class.
39
+ # Useful for very thin, generic Ruby classes for Data models.
40
+ def attribute(getter_name, default=nil)
41
+
42
+ # Define a getter on the object
43
+ define_method(getter_name) do
44
+
45
+ target = send(self.class.attributes_proxy)
46
+
47
+ return target[getter_name] unless target.respond_to?(:has_key?)
48
+
49
+ if target.has_key?(getter_name)
50
+ target[getter_name]
51
+ else
52
+ self.class.attribute_defaults[getter_name]
53
+ end
54
+ end
55
+
56
+ # Define a setter on the object
57
+ define_method("#{getter_name}=") do |value|
58
+ send(self.class.attributes_proxy)[getter_name] = value
59
+ end
60
+
61
+ # Define a default on the object
62
+ attribute_defaults[getter_name] = default
63
+
64
+ end
65
+
66
+ # Defines where the attributes are stored for the target class.
67
+ def set_attributes_proxy(value)
68
+ @attributes_proxy = value
69
+ end
70
+
71
+ def attributes_proxy
72
+ @attributes_proxy ||= :attributes
73
+ end
74
+
75
+ def attribute_defaults
76
+ @attribute_defaults ||= {}
77
+ end
78
+ end
79
+
80
+ module InstanceMethods
81
+
82
+ # Defines an attributes getter and defaults it to a Hash.
83
+ def attributes
84
+ @attributes ||= {}
85
+ end
86
+
87
+ end
88
+
89
+ end # AttributeSystem
90
+
91
+ end # Fathom
@@ -0,0 +1,28 @@
1
+ module Fathom
2
+ module ContextBehavior
3
+
4
+ module ClassMethods
5
+
6
+ def default_class(value=nil)
7
+ @default_class = value if value
8
+ @default_class
9
+ end
10
+
11
+ def new(*attrs, &block)
12
+ target = attrs.shift
13
+ target ||= default_class.new if default_class
14
+ raise ArgumentError, "You must provide a target object to build this context." unless target
15
+ obj = super(*attrs, &block)
16
+ obj.send(:instance_variable_set, :@object, target)
17
+ obj
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ attr_reader :object
23
+ end
24
+
25
+ def self.configure(base)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ module Fathom
2
+ module Plugins
3
+ def plugins
4
+ @plugins ||= []
5
+ end
6
+
7
+ def plugin(mod)
8
+ include mod unless mod.const_defined?(:InstanceMethods)
9
+ extend mod::ClassMethods if mod.const_defined?(:ClassMethods)
10
+ include mod::InstanceMethods if mod.const_defined?(:InstanceMethods)
11
+ mod.configure(self) if mod.respond_to?(:configure)
12
+ plugins << mod
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,47 @@
1
+ module Fathom
2
+ class NetworkPopulation
3
+ # ============
4
+ # = Behavior =
5
+ # ============
6
+ extend Plugins
7
+ plugin ContextBehavior
8
+ default_class Network
9
+
10
+ # Uses YAML to populate a network.
11
+ # Expects a format in the YAML that mirrors the data models we are using.
12
+ #
13
+ # Dependencies:
14
+ # * yaml (standard library)
15
+ # * open-uri (standard library)
16
+ #
17
+ # Roles: NetworkBuilder
18
+ #
19
+ # Usage:
20
+ # @context = NetworkPopulation.new(some_network)
21
+ # @context.import_records_from_yaml(:filename => 'some_network.yml')
22
+ def import_records_from_yaml(opts={})
23
+ require 'yaml'
24
+ require 'open-uri'
25
+ object.extend NetworkBuilder
26
+ hash = extract_data_hash_from_parameters(opts)
27
+ object.from_hash(hash)
28
+ end
29
+
30
+ protected
31
+
32
+ # Contract: return a hash, the best one you can find, or an empty one.
33
+ def extract_data_hash_from_parameters(opts)
34
+ if opts[:filename]
35
+ data_from_yaml_file(opts[:filename])
36
+ else
37
+ {}
38
+ end
39
+ end
40
+
41
+ # Contract: return a hash or raise an error
42
+ def data_from_yaml_file(filename)
43
+ YAML.load_file(filename)
44
+ end
45
+
46
+ end
47
+ end