taxonomite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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>.