taxonomite 0.1.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 (111) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +30 -0
  3. data/lib/taxonomite.rb +6 -0
  4. data/lib/taxonomite/entity.rb +39 -0
  5. data/lib/taxonomite/exceptions.rb +7 -0
  6. data/lib/taxonomite/node.rb +158 -0
  7. data/lib/taxonomite/taxonomite_configuration.rb +17 -0
  8. data/lib/taxonomite/tree.rb +130 -0
  9. data/lib/taxonomite/version.rb +3 -0
  10. data/spec/controllers/taxonomite/taxonomite_controller_spec.rb +31 -0
  11. data/spec/dummy/README.rdoc +28 -0
  12. data/spec/dummy/Rakefile +6 -0
  13. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  14. data/spec/dummy/app/assets/stylesheets/application.css +19 -0
  15. data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
  16. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  17. data/spec/dummy/app/controllers/taxonomite_controller.rb +226 -0
  18. data/spec/dummy/app/helpers/application_helper.rb +13 -0
  19. data/spec/dummy/app/helpers/taxonomite_helper.rb +9 -0
  20. data/spec/dummy/app/views/layouts/application.html.erb +22 -0
  21. data/spec/dummy/app/views/shared/_error_messages.html.erb +14 -0
  22. data/spec/dummy/app/views/shared/_flash_messages.html.erb +9 -0
  23. data/spec/dummy/app/views/taxonomite/_node.html.erb +6 -0
  24. data/spec/dummy/app/views/taxonomite/edit.html.erb +49 -0
  25. data/spec/dummy/app/views/taxonomite/index.html.erb +9 -0
  26. data/spec/dummy/app/views/taxonomite/new.html.erb +16 -0
  27. data/spec/dummy/app/views/taxonomite/show.html.erb +28 -0
  28. data/spec/dummy/bin/bundle +3 -0
  29. data/spec/dummy/bin/rails +4 -0
  30. data/spec/dummy/bin/rake +4 -0
  31. data/spec/dummy/bin/setup +29 -0
  32. data/spec/dummy/config.ru +4 -0
  33. data/spec/dummy/config/application.rb +35 -0
  34. data/spec/dummy/config/boot.rb +5 -0
  35. data/spec/dummy/config/environment.rb +5 -0
  36. data/spec/dummy/config/environments/development.rb +38 -0
  37. data/spec/dummy/config/environments/production.rb +76 -0
  38. data/spec/dummy/config/environments/test.rb +42 -0
  39. data/spec/dummy/config/initializers/assets.rb +11 -0
  40. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  41. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  42. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  43. data/spec/dummy/config/initializers/inflections.rb +16 -0
  44. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  45. data/spec/dummy/config/initializers/mongoid.rb +8 -0
  46. data/spec/dummy/config/initializers/session_store.rb +3 -0
  47. data/spec/dummy/config/initializers/wrap_parameters.rb +10 -0
  48. data/spec/dummy/config/locales/en.yml +23 -0
  49. data/spec/dummy/config/mongoid.yml +103 -0
  50. data/spec/dummy/config/routes.rb +10 -0
  51. data/spec/dummy/config/secrets.yml +22 -0
  52. data/spec/dummy/lib/tasks/db_populate.rake +66 -0
  53. data/spec/dummy/lib/util.rb +28 -0
  54. data/spec/dummy/log/development.log +7169 -0
  55. data/spec/dummy/log/test.log +915 -0
  56. data/spec/dummy/public/404.html +67 -0
  57. data/spec/dummy/public/422.html +67 -0
  58. data/spec/dummy/public/500.html +66 -0
  59. data/spec/dummy/public/favicon.ico +0 -0
  60. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/-rejHCRn0GBGCrHMyZAcq10cNOCXaG4dVN13pFMvLgA.cache +0 -0
  61. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/1TWMTorbA_3E6hatKbP5T9n5oDSeVMk68LF8CRn1JjI.cache +1 -0
  62. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/3B4hMNppXANClZ-lGO7Jps_MbXOz_GLxSqnastPo3Sg.cache +0 -0
  63. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/8H7HwvVynNVZNgOjRJ5eAUqlWB8-oDl9VwBJlQSTBQw.cache +2 -0
  64. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/8y77NTXIYLg5cxm011nNxQAil9n5WVHkcp3HuxsFBMY.cache +0 -0
  65. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/AmhMJ3oocG6mNJTk0T7UZTZNv6MhN1nj2WL-k__XZlI.cache +1 -0
  66. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/CbVJZSB6kte1IYJqiASuO95NmINClhlHaFdLKMor0c0.cache +1 -0
  67. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/D05VjCHQqo1_JqnZLVivHPybbW2MCDXAQTDeLMBqYIQ.cache +2 -0
  68. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/GalDJvDt8BphTIma_xp93plZ7ay3K9A9uJk3txZw_00.cache +0 -0
  69. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/HMK_AuhVBxFLR6tGFGS75xvUQp8JlDZBwUddr14DleY.cache +1 -0
  70. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/Hac0rR46nAtlqEtr6S-s7g79TUGQAKO_jxYLbyARW4k.cache +0 -0
  71. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/IygAr9Ty7v-NJrroesXGkla15XgRR3nUI7BVZaPZigk.cache +0 -0
  72. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/K46UGuIKOnMfRnYBSmbjd8UJ9LfdCS5OBhkXG00GCvY.cache +1 -0
  73. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/KVHAw7mbk0REIRf0Zrv40JhknZB1lVmcExhj4bfZduY.cache +0 -0
  74. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/LhBEGJtsniGETE6aGB-IrzlM_CxS6iAfBviyrUM2AvA.cache +0 -0
  75. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/PzbUQc7wYDmhK5RZzXNRAHPhpwryEK2aIRRUfbsFMjw.cache +1 -0
  76. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/Q2QIHypAobobCW8WZnDEKFQqFczCiXaPAf3Hgk9MA_o.cache +1 -0
  77. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/RnBEbAuuDsDqp3JRLnX8pp-IHFk1d1rGbXxYy6DhkY4.cache +1 -0
  78. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/TIm2-xmbi7CMNL3syzvG5LyRxJtycIGXtwz8Mco3sdA.cache +0 -0
  79. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/U-xdOqbEKMZubNF_Mq_pBnN5uGgDj_w3I9193KH2XIE.cache +1 -0
  80. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/ZEWFmXe3i1eUOHbMoM_K0-6G0ejgZCWT3qF9dyjYEzQ.cache +0 -0
  81. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/_k3G10-SEe8_SHlmwYbslXN42uDRmFGK0Q7nR3VyH7s.cache +2 -0
  82. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/bkkgBW_hSRUeyxOZ8u-7Artvy3oCRMUtd0iTsd8wrtk.cache +0 -0
  83. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/bpttkziOegeD-17ihmHMccaVxwU9_YMeXXsmFpQQh2E.cache +1 -0
  84. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/c0embYAEeyo6qdjqQ-b8QNzuj70uZn-q1c-dhX4aeaQ.cache +0 -0
  85. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/dbpC0p6RBdyEjXhOxUegedCy8aK12GwuakY1DqzSB1k.cache +1 -0
  86. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/exOsm6yrmkOg_T82Brjsyr-e2U5HAJCqiPy1NJjPBJg.cache +0 -0
  87. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/f7S__u6qEm3h40_nJwEAwibtxI3vV-uWkuJAdnyIEho.cache +0 -0
  88. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/lEOEeQNsy0n89Y25rZEAe5P6zFLjkhRpxQ2ZEfi_giM.cache +1 -0
  89. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/m_RzwKTs1azS37mZ7W1stXJCfGBM4xF-Pge7trJaXhY.cache +1 -0
  90. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/nMQn6BRwxARa2nhmNQEdm_5xj6tr2XYpLzE_7Eac2h4.cache +1 -0
  91. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/nl0sTVgLFpHD_1Q4c8NGcatzmud7AWL6yin3iSgziRc.cache +2 -0
  92. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/rKpLfQIjRPLcR43VeI7lwjxj1BWPcxjVoSyDmJru04o.cache +1 -0
  93. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/rhofdc-dVgpC_YOqzpz2yMRHD9LW4sIGBcPdzR-uM6E.cache +1 -0
  94. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/sjZWL1ZezAb-_PmJJS_5mi-Q9X1Jcic0D7F33sUC3vs.cache +0 -0
  95. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/tLUV7eduShLmpqrXfsgemL-zKEBEQQDdqUw-MGoqMA0.cache +0 -0
  96. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/uYLC0l4_HXjqNdRF2mvEqpdcIsQgz0XVMe9YxQ3dnlc.cache +1 -0
  97. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/voPvH6F_x-d5fK63I1IjMzEfTcybOHN-g9q3x4BIGGw.cache +1 -0
  98. data/spec/factories/entity.rb +13 -0
  99. data/spec/factories/taxonomy_taxon.rb +45 -0
  100. data/spec/models/taxonomite/entity_spec.rb +34 -0
  101. data/spec/models/taxonomite/hierarchy_spec.rb +34 -0
  102. data/spec/models/taxonomite/model_spec.rb +39 -0
  103. data/spec/models/taxonomite/taxonomite_spec.rb +11 -0
  104. data/spec/models/taxonomite/tree_spec.rb +56 -0
  105. data/spec/models/taxonomite/zoology.rb +119 -0
  106. data/spec/rails_helper.rb +53 -0
  107. data/spec/spec_helper.rb +32 -0
  108. data/spec/taxonomite_helper.rb +5 -0
  109. data/spec/views/taxonomite/taxonomite/index.html.erb_spec.rb +5 -0
  110. data/spec/views/taxonomite/taxonomite/show.html.erb_spec.rb +5 -0
  111. metadata +456 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 23b3b1dfb04a5bba6964518d64495f5ce765a401
4
+ data.tar.gz: 8b97678d947fb2f0fea89b2298885bad97e01f61
5
+ SHA512:
6
+ metadata.gz: ab087ff6284c6b3208d6dc1be6b64aa6cd47c0464f5dbc9cd3abc4074f8fdfdd7c0685118350b98393bbb5f42534b7a042d47211927b778a36cf4b33427dfc34
7
+ data.tar.gz: 263d4a6ca733fad72e9074e6c852f4d36da4a00324c85523671ffa8a246c97c3982b3a193f96c01a40a40a9031d79dc5f1407040f0a4f8c7ecba740d6c8883ce
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ require 'bundler/gem_tasks'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+ require 'rspec/core/rake_task'
9
+ require 'rdoc/task'
10
+
11
+ # APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
12
+
13
+ Bundler::GemHelper.install_tasks
14
+ #Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
15
+
16
+ desc "Run all specs in spec directory (excluding plugin specs)"
17
+ RSpec::Core::RakeTask.new(:spec) do |task|
18
+ task.rspec_opts = ['--color', '--format', 'documentation']
19
+ end
20
+
21
+ # RDoc tasks
22
+ RDoc::Task.new(:rdoc) do |rdoc|
23
+ rdoc.rdoc_dir = 'rdoc'
24
+ rdoc.title = 'Places'
25
+ rdoc.options << '--line-numbers'
26
+ rdoc.rdoc_files.include('README.rdoc')
27
+ rdoc.rdoc_files.include('lib/**/*.rb')
28
+ end
29
+
30
+ task :default => :spec
data/lib/taxonomite.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'taxonomite/node'
2
+ require 'taxonomite/entity'
3
+
4
+ # Taxonomite module
5
+ module Taxonomite
6
+ end
@@ -0,0 +1,39 @@
1
+ # entity.rb
2
+
3
+ require 'active_support/concern'
4
+
5
+ module Taxonomite
6
+ module Entity
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ has_one :taxonomy_node, class_name: 'Taxonomite::Node', as: :owner, validate: true
11
+ before_save :do_setup
12
+
13
+ class_eval "def base_class; ::#{self.name}; end"
14
+ end
15
+
16
+ def get_taxonomy_node
17
+ if (self.taxonomy_node == nil)
18
+ self.taxonomy_node = self.create_taxonomy_node
19
+ end
20
+ self.taxonomy_node
21
+ end
22
+
23
+ protected
24
+ # classes overload to create the appropriate taxonomy_node
25
+ # def create_taxonomy_node
26
+ # Taxonomite::Node.new(name: self.name)
27
+ # end
28
+
29
+ private
30
+ # subclasses should overload create_taxonomy_node to create the appropriate Place object and set it up
31
+ def do_setup
32
+ if (self.taxonomy_node == nil)
33
+ self.taxonomy_node = self.respond_to?(:create_taxonomy_node) ? self.create_taxonomy_node : Taxonomite::Node.new(name: self.name)
34
+ self.taxonomy_node.owner = self
35
+ end
36
+ end
37
+
38
+ end # module Location
39
+ end # module Places
@@ -0,0 +1,7 @@
1
+ # taxonomite/exceptions.rb
2
+
3
+ module Taxonomite
4
+ class InvalidChild < RuntimeError; end
5
+ class InvalidParent < RuntimeError; end
6
+ class CircularRelation < RuntimeError; end
7
+ end # taxonomite
@@ -0,0 +1,158 @@
1
+ require 'taxonomite/taxonomite_configuration'
2
+ require 'taxonomite/tree'
3
+
4
+ module Taxonomite
5
+ class Node
6
+ # Class declarations
7
+ #
8
+ # configuration
9
+ #
10
+ # !! note that configuration is class-wide, rather than on an
11
+ # instance-instance value; this could be changed, for example if
12
+ # two simultaneous persistence models for the place were desired
13
+ #
14
+ class << self
15
+ attr_writer :configiration
16
+ end
17
+
18
+ def self.config
19
+ @configuration ||= Taxonomite::Configuration.new
20
+ end
21
+
22
+ def self.configure
23
+ yield(config)
24
+ end
25
+
26
+ def self.reset
27
+ @configuration = Taxonomite::Configuration.new
28
+ end
29
+
30
+ def self.primary_key
31
+ "_id"
32
+ end
33
+
34
+ case Node.config.use_tree_model
35
+ when :self
36
+ include ::Mongoid::Document
37
+ include Taxonomite::Tree
38
+
39
+ # configure the way the tree behaves
40
+ before_destroy :nullify_children
41
+ else
42
+ raise RuntimeError, 'Invalid option for Node.config.use_tree_model: #{Node.config.use_tree_model}'
43
+ end
44
+
45
+ field :name, type: String # name of this particular object (not really node)
46
+ field :description, type: String # description of this item
47
+ field :entity_type, type: String, default: ->{ self.get_entity_type } # type of entity (i.e. state, county, city, etc.)
48
+
49
+ belongs_to :owner, polymorphic: true # this is the associated object
50
+
51
+ ## Data collection methods
52
+
53
+ # aggregates the results of calling method m on all leaves of the tree and returns that
54
+ def aggregate_leaves(m)
55
+ if self.leaf?
56
+ return self.owner.instance_eval(m) if self.owner != nil && self.owner.respond_to?(m)
57
+ return self.instance_eval(m) if self.respond_to?(m)
58
+ return 0
59
+ else
60
+ res = 0
61
+ self.children.each do |c|
62
+ res = res + c.aggregate_leaves(m)
63
+ end
64
+ return res
65
+ end
66
+ end
67
+
68
+ ## Typeification methods
69
+
70
+ # typeify name w entity (i.e. 'Washington state' vs. 'Seattle')
71
+ def typeifiedname
72
+ s = self.name
73
+ s += (" " + self.entity_type.capitalize) if self.includetypeinname?
74
+ return s
75
+ end
76
+
77
+ # subclasses should override to make sure the parent is appropriate for this child
78
+ # !! could move this to the tree structure
79
+ def is_valid_parent?(pa)
80
+ # !! need to figure out how to do this with regexp
81
+ unless self.invalid_parent_types.include?(pa.entity_type)
82
+ s = self.valid_parent_types
83
+ if s.include?('*')
84
+ return true
85
+ else
86
+ return s.include?(pa.entity_type)
87
+ end
88
+ else
89
+ return false
90
+ end
91
+ end
92
+
93
+ # check for validity, with adding error checking this would be the appropriate
94
+ # place to add exceptions, etc. (to allow recovery);
95
+ # !! could move this to the tree structure
96
+ def is_valid_child?(ch)
97
+ # !! need to figure out how to do this with regexp
98
+ unless self.invalid_child_types.include?(ch.entity_type)
99
+ s = self.valid_child_types
100
+ if s.include?('*') || s.include?(ch.entity_type)
101
+ return ch.is_valid_parent?(self)
102
+ else
103
+ return false
104
+ end
105
+ else
106
+ return false
107
+ end
108
+ end
109
+
110
+ # default parent types (subclasses should override as needed) - default specifies any
111
+ def valid_parent_types
112
+ '*'
113
+ end
114
+
115
+ # default child types (subclasses should override as needed) - default specifies any
116
+ def valid_child_types
117
+ '*'
118
+ end
119
+
120
+ # default invalid child types
121
+ def invalid_child_types
122
+ ""
123
+ end
124
+
125
+ # default invalid parent types
126
+ def invalid_parent_types
127
+ ""
128
+ end
129
+
130
+ # don't want to index off of place name? - could have multiple entries w. similar names
131
+ # create an index off of the place name, alone; will later create on off of the
132
+ # geo locations *additionally*
133
+ # index({ place_name: 1 }, { unique: false, name: "name_index"})
134
+
135
+ # ** would like to hide these interfaces in a private/protected manner, not clear
136
+ # ** how to do this in Ruby - doesn't have 'const' access similar to c++, etc.
137
+ protected
138
+
139
+ # include type in the name of this place (i.e. 'Washington state')
140
+ def includetypeinname?
141
+ return false
142
+ end
143
+
144
+ # set the entity type (each subclass should override)
145
+ def get_entity_type
146
+ 'Node'
147
+ end
148
+
149
+ def validate_child(ch)
150
+ raise InvalidChild, "Cannot add #{ch.name} (#{ch.entity_type}) as child of #{self.name} (#{self.entity_type})" if !is_valid_child?(ch)
151
+ end
152
+
153
+ def validate_parent(pa)
154
+ raise InvalidParent, "Cannot add #{pa.name} (#{pa.enity_type}) as parent of #{self.name} (#{self.entity_type})" if !is_valid_parent?(pa)
155
+ end
156
+
157
+ end # class Node
158
+ end # module Taxonomite
@@ -0,0 +1,17 @@
1
+ # taxonomite_configuration.rb
2
+ # hold configuration parameters for the library
3
+ #
4
+
5
+ module Taxonomite
6
+ class Configuration
7
+ # future versions may extend to using different tree models
8
+ # - for now uses a custom tree model (:self)
9
+ attr_accessor :use_tree_model
10
+
11
+ protected
12
+ # initialize
13
+ def initialize
14
+ @use_tree_model = :self
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,130 @@
1
+ # taxonomite_tree.rb
2
+
3
+ require 'active_support/concern'
4
+ require 'taxonomite/exceptions'
5
+
6
+ module Taxonomite
7
+ module Tree
8
+ extend ActiveSupport::Concern
9
+
10
+ # this is what will be included in the class that uses this
11
+ #
12
+ included do
13
+ has_many :children, :class_name => self.name, :inverse_of => :parent, :before_add => :validate_child!
14
+ belongs_to :parent, :class_name => self.name, :inverse_of => :children
15
+
16
+ # this allows for faster database searchign when adding/checking validity
17
+ # !! not implemented field :parent_ids, :type => Array, :default => []
18
+
19
+ class_eval "def base_class; ::#{self.name}; end"
20
+ end
21
+
22
+ module ClassMethods
23
+ # find all roots for this tree (Mongoid query)
24
+ def roots
25
+ where(:parent_id => nil)
26
+ end
27
+
28
+ # find all leaves fro this tree (Mongoid query)
29
+ def leaves
30
+ where(:_id.nin => only(:parent_id).collect(&:parent_id))
31
+ end
32
+ end
33
+
34
+ # is this a root node?
35
+ def root?
36
+ self.parent == nil
37
+ end
38
+
39
+ # is this a leaf?
40
+ def leaf?
41
+ self.children.empty?
42
+ end
43
+
44
+ # find the root of this node
45
+ def root
46
+ self.root? ? self : self.parent.root
47
+ end
48
+
49
+ # is the object an ancestor of nd?
50
+ def is_ancestor?(nd)
51
+ self.root? ? false : (self.parent == nd || self.parent.is_ancestor?(nd))
52
+ end
53
+
54
+ # is this an ancestor of another node?
55
+ def ancestor_of?(nd)
56
+ nd.is_ancestor?(self)
57
+ end
58
+
59
+ # is this a descendant of nd?
60
+ def descendant_of?(nd)
61
+ (self == nd) ? true : is_ancestor?(nd)
62
+ end
63
+
64
+ # return a chainable Mongoid criteria to get all descendants
65
+ def descendants
66
+ doc = Array.new
67
+ children.each do |c|
68
+ doc += [c] + c.descendants
69
+ end
70
+ return doc
71
+ end
72
+
73
+ # return a chainable Mongoid criteria to get self + all descendants
74
+ def self_and_descendants
75
+ [self] + self.descendants
76
+ end
77
+
78
+ # nullifies all children's parent id (cuts link)
79
+ def nullify_children
80
+ children.each do |c|
81
+ c.parent = nil
82
+ c.save
83
+ end
84
+ end
85
+
86
+ # delete children; this *removes all of the children fromt he data base (and ensuing)
87
+ def destroy_children
88
+ children.destroy_all
89
+ end
90
+
91
+ # move all children to the parent node
92
+ def move_children_to_parent
93
+ children.each do |c|
94
+ self.parent.children << c
95
+ c.parent = self.parent # is this necessary?
96
+ end
97
+ end
98
+
99
+ # perform validation on whether this child is an acceptable child or not?
100
+ # the base_class must have a method 'is_valid_child?' to implement domain logic there
101
+ def validate_child!(ch)
102
+ raise InvalidChild "Attempted to add nil child to #{self}" if (ch == nil)
103
+ raise CircularRelation, "Circular relationship adding #{ch} to #{self}" if self.descendant_of?(ch)
104
+ if base_class.method_defined? :is_valid_child?
105
+ self.validate_child(ch) # this should throw an error if not valid
106
+ end
107
+ end
108
+
109
+ # perform validation on whether this parent is an acceptable parent or not?
110
+ # the base_class should have a method 'is_valid_parent?' to invoke domain logic
111
+ # calls - invalid_parent_error(ch), if it exists, if the parent is invalid (for error handling)
112
+ # def validate_parent(pa)
113
+ # if (pa == nil) || (pa == self)
114
+ # self.invalid_parent_error(pa)
115
+ # else
116
+ # while par != nil do
117
+ # unless self.is_valid_parent(pa)
118
+ # end
119
+ # end
120
+ # end
121
+ # end
122
+
123
+ # to do - find a way to add a Mongoid criteria to return all of the nodes for this object
124
+ # descendants
125
+ # descendants_and_self
126
+ # ancestors
127
+ # ancestors_and_self
128
+
129
+ end # Tree
130
+ end # Taxonomite
@@ -0,0 +1,3 @@
1
+ module Taxonomite
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,31 @@
1
+ require 'rails_helper'
2
+ require 'spec_helper'
3
+ require 'taxonomite/node'
4
+
5
+ module Taxonomite
6
+
7
+ RSpec.describe TaxonomiteController, type: :controller do
8
+
9
+ before :all do
10
+ # populate the database prior to trying index/get
11
+ @sample = FactoryGirl.create(:taxonomite_node)
12
+ end
13
+
14
+ describe "GET #index" do
15
+ it "returns http success" do
16
+ get :index
17
+ expect(response).to have_http_status(:success)
18
+ end
19
+ end
20
+
21
+ # really just test that an invalid id (=1) fails
22
+ describe "GET #show" do
23
+ it "returns http success" do
24
+ get :show, :id => @sample.id
25
+ expect(response).to have_http_status(:success)
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.