specify_cli 0.0.5

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 (106) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +17 -0
  5. data/Gemfile.lock +117 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.rdoc +43 -0
  8. data/Rakefile +15 -0
  9. data/bin/specify_cli +248 -0
  10. data/lib/specify.rb +45 -0
  11. data/lib/specify/branch_parser.rb +85 -0
  12. data/lib/specify/cli.rb +11 -0
  13. data/lib/specify/cli/database_setup.rb +46 -0
  14. data/lib/specify/cli/stubs.rb +63 -0
  15. data/lib/specify/cli/viewset.rb +21 -0
  16. data/lib/specify/configuration.rb +12 -0
  17. data/lib/specify/configuration/config.rb +120 -0
  18. data/lib/specify/configuration/db_config.rb +162 -0
  19. data/lib/specify/configuration/host_config.rb +37 -0
  20. data/lib/specify/database.rb +140 -0
  21. data/lib/specify/models.rb +43 -0
  22. data/lib/specify/models/accession.rb +33 -0
  23. data/lib/specify/models/agent.rb +138 -0
  24. data/lib/specify/models/app_resource_data.rb +32 -0
  25. data/lib/specify/models/app_resource_dir.rb +43 -0
  26. data/lib/specify/models/auto_numbering_scheme.rb +94 -0
  27. data/lib/specify/models/collecting_event.rb +38 -0
  28. data/lib/specify/models/collection.rb +67 -0
  29. data/lib/specify/models/collection_object.rb +127 -0
  30. data/lib/specify/models/createable.rb +21 -0
  31. data/lib/specify/models/determination.rb +63 -0
  32. data/lib/specify/models/discipline.rb +61 -0
  33. data/lib/specify/models/division.rb +26 -0
  34. data/lib/specify/models/geography.rb +5 -0
  35. data/lib/specify/models/geography/administrative_division.rb +32 -0
  36. data/lib/specify/models/geography/geographic_name.rb +66 -0
  37. data/lib/specify/models/geography/geography.rb +23 -0
  38. data/lib/specify/models/institution.rb +13 -0
  39. data/lib/specify/models/locality.rb +50 -0
  40. data/lib/specify/models/preparation.rb +53 -0
  41. data/lib/specify/models/preparation_type.rb +30 -0
  42. data/lib/specify/models/record_set.rb +55 -0
  43. data/lib/specify/models/record_set_item.rb +29 -0
  44. data/lib/specify/models/taxonomy.rb +6 -0
  45. data/lib/specify/models/taxonomy/common_name.rb +14 -0
  46. data/lib/specify/models/taxonomy/rank.rb +31 -0
  47. data/lib/specify/models/taxonomy/taxon.rb +54 -0
  48. data/lib/specify/models/taxonomy/taxonomy.rb +21 -0
  49. data/lib/specify/models/tree_queryable.rb +55 -0
  50. data/lib/specify/models/updateable.rb +20 -0
  51. data/lib/specify/models/user.rb +104 -0
  52. data/lib/specify/models/view_set_object.rb +32 -0
  53. data/lib/specify/number_format.rb +60 -0
  54. data/lib/specify/services.rb +18 -0
  55. data/lib/specify/services/service.rb +51 -0
  56. data/lib/specify/services/stub_generator.rb +291 -0
  57. data/lib/specify/services/view_loader.rb +177 -0
  58. data/lib/specify/session.rb +77 -0
  59. data/lib/specify/user_type.rb +61 -0
  60. data/lib/specify/version.rb +19 -0
  61. data/man/specify_cli-database.1 +60 -0
  62. data/man/specify_cli-database.1.html +137 -0
  63. data/man/specify_cli-database.1.ronn +53 -0
  64. data/man/specify_cli-repository.1 +55 -0
  65. data/man/specify_cli-repository.1.html +128 -0
  66. data/man/specify_cli-repository.1.ronn +42 -0
  67. data/man/specify_cli-stubs.1 +177 -0
  68. data/man/specify_cli-stubs.1.html +239 -0
  69. data/man/specify_cli-stubs.1.ronn +147 -0
  70. data/man/specify_cli-viewset.1 +92 -0
  71. data/man/specify_cli-viewset.1.html +154 -0
  72. data/man/specify_cli-viewset.1.ronn +72 -0
  73. data/man/specify_cli.1 +213 -0
  74. data/man/specify_cli.1.html +252 -0
  75. data/man/specify_cli.1.ronn +157 -0
  76. data/spec/branch_parser_spec.rb +94 -0
  77. data/spec/cli/stubs_spec.rb +44 -0
  78. data/spec/configuration/config_spec.rb +269 -0
  79. data/spec/configuration/db_config_spec.rb +299 -0
  80. data/spec/configuration/host_config_spec.rb +64 -0
  81. data/spec/database_spec.rb +83 -0
  82. data/spec/examples.txt +217 -0
  83. data/spec/helpers.rb +15 -0
  84. data/spec/models/app_resource_data_spec.rb +38 -0
  85. data/spec/models/app_resource_dir_spec.rb +8 -0
  86. data/spec/models/auto_numbering_scheme_spec.rb +78 -0
  87. data/spec/models/collection_object_spec.rb +92 -0
  88. data/spec/models/collection_spec.rb +32 -0
  89. data/spec/models/discipline_spec.rb +31 -0
  90. data/spec/models/record_set_spec.rb +18 -0
  91. data/spec/models/user_spec.rb +182 -0
  92. data/spec/models/view_set_object_spec.rb +70 -0
  93. data/spec/number_format_spec.rb +43 -0
  94. data/spec/services/stub_generator_spec.rb +635 -0
  95. data/spec/services/view_loader_spec.rb +436 -0
  96. data/spec/session_spec.rb +105 -0
  97. data/spec/spec_helper.rb +116 -0
  98. data/spec/support/db.yml +12 -0
  99. data/spec/support/stub.yaml +17 -0
  100. data/spec/support/stub_locality.yaml +19 -0
  101. data/spec/support/viewsets/paleo.views.xml +30 -0
  102. data/spec/support/viewsets/paleo.xml +30 -0
  103. data/spec/user_type_spec.rb +79 -0
  104. data/specify_cli.gemspec +27 -0
  105. data/specify_cli.rdoc +1 -0
  106. metadata +246 -0
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specify
4
+ module Model
5
+ # AutoNumberingSchemes represent automatically incrementable numbers
6
+ # (serial numbers such as catalog numbers or accession numbers).
7
+ #
8
+ # An AutoNumberingScheme is scoped to one or more #collections
9
+ # (instances of Specify::Model::Collection) in the case of catalog numbers,
10
+ # one or more #divisions (instances of Specify::Model::Division) in the case
11
+ # of accession numbers. Serial numbers (_incrementers_) will be incremented
12
+ # across that scope.
13
+ #
14
+ # An AutoNumberingScheme has a #number_format (an instance of
15
+ # Specify::NumberFormat) that determines the format of the number
16
+ # (auto-numbers in _Specify_ are strings).
17
+ class AutoNumberingScheme < Sequel::Model(:autonumberingscheme)
18
+ include Createable
19
+ include Updateable
20
+
21
+ many_to_one :created_by,
22
+ class: 'Specify::Model::Agent',
23
+ key: :CreatedByAgentID
24
+ many_to_one :modified_by,
25
+ class: 'Specify::Model::Agent',
26
+ key: :ModifiedByAgentID
27
+ many_to_many :collections,
28
+ left_key: :AutoNumberingSchemeID,
29
+ right_key: :CollectionID,
30
+ join_table: :autonumsch_coll
31
+ many_to_many :disciplines,
32
+ left_key: :AutoNumberingSchemeID,
33
+ right_key: :DisciplineID,
34
+ join_table: :autonumsch_dsp
35
+ many_to_many :divisions,
36
+ left_key: :AutoNumberingSchemeID,
37
+ right_key: :DivisionID,
38
+ join_table: :autonumsch_div
39
+
40
+ # Returns +true+ if +self+ applies to catalog numbers.
41
+ def catalog_number?
42
+ scheme_model == CollectionObject && scheme_type == :catalog_number
43
+ end
44
+
45
+ # Returns the next available serial number in the scope of the scheme,
46
+ # formatted according to the #number_format.
47
+ def increment
48
+ @number_format ||= number_format
49
+ @number_format.create(@number_format.incrementer(max) + 1)
50
+ end
51
+
52
+ # Returns the currently highest number within the scope of self.
53
+ # Currently only supports catalog numbers.
54
+ def max
55
+ raise 'not implemented' unless catalog_number?
56
+ collections.map(&:highest_catalog_number).compact.max
57
+ end
58
+
59
+ # Returns the Specify::NumberFormat instance for the +self+.
60
+ def number_format
61
+ # TODO: get proper number format from xml
62
+ case self.FormatName
63
+ when 'CatalogNumberNumeric'
64
+ NumberFormat.new
65
+ end
66
+ end
67
+
68
+ # Returns the model class the numbering scheme applies to;
69
+ # Specify::Model::CollectionObject for catalog numbers,
70
+ # Specify::Model::Accession for accession numbers.
71
+ def scheme_model
72
+ case self.TableNumber
73
+ when 1
74
+ CollectionObject
75
+ when 7
76
+ Accession
77
+ end
78
+ end
79
+
80
+ # Returns a symbol for the type of numbering scheme
81
+ # (+:catalog_number+, +accession_number+, or +:custom+).
82
+ def scheme_type
83
+ case self.SchemeName
84
+ when 'Catalog Numbering Scheme'
85
+ :catalog_number
86
+ when 'Accession Numbering Scheme'
87
+ :accession_number
88
+ else
89
+ :custom
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specify
4
+ module Model
5
+ # CollectingEvents hold information about when, where, how, and by whom a
6
+ # Specify::Model::CollectionObject was collected.
7
+ #
8
+ # A CollectingEvent takes place in (has one) Specify::Model::Locality
9
+ # (_where_ it was collected).
10
+ #
11
+ # A CollectingEvent can have one or many #collection_objects, depending
12
+ # on the value of Specify::Model::Collection#embedded_collecting_event? for
13
+ # the collection an associated CollectionObject belongs to.
14
+ class CollectingEvent < Sequel::Model(:collectingevent)
15
+ include Createable
16
+ include Updateable
17
+
18
+ many_to_one :discipline,
19
+ key: :DisciplineID
20
+ many_to_one :locality,
21
+ key: :LocalityID
22
+ one_to_many :collection_objects,
23
+ key: :CollectingEventID
24
+ many_to_one :created_by,
25
+ class: 'Specify::Model::Agent',
26
+ key: :CreatedByAgentID
27
+ many_to_one :modified_by,
28
+ class: 'Specify::Model::Agent',
29
+ key: :ModifiedByAgentID
30
+
31
+ # Sequel hook that assigns a GUID.
32
+ def before_create
33
+ self[:GUID] = SecureRandom.uuid
34
+ super
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specify
4
+ module Model
5
+ # Collections are the lowest level of scope in a Specify::Database.
6
+ #
7
+ # A Collection belongs to the a Specify::Model::Discipline.
8
+ #
9
+ # A Collection contains all instances of Specify::Model::CollectionObject
10
+ # belonging to that collection.
11
+ class Collection < Sequel::Model(:collection)
12
+ include Updateable
13
+
14
+ many_to_one :discipline,
15
+ key: :DisciplineID
16
+ one_to_many :collection_objects,
17
+ key: :CollectionID
18
+ one_to_many :preparation_types,
19
+ key: :CollectionID
20
+ one_to_many :record_sets,
21
+ key: :CollectionMemberID
22
+ one_to_many :app_resource_dirs,
23
+ class: 'Specify::Model::AppResourceDir',
24
+ key: :CollectionID
25
+ one_through_one :auto_numbering_scheme,
26
+ left_key: :CollectionID,
27
+ right_key: :AutoNumberingSchemeID,
28
+ join_table: :autonumsch_coll
29
+ one_to_one :view_set_dir,
30
+ class: 'Specify::Model::AppResourceDir',
31
+ key: :CollectionID do |ds|
32
+ ds.where(discipline: discipline,
33
+ UserType: nil,
34
+ IsPersonal: false)
35
+ end
36
+
37
+ # Returns +false+ if Specify::Model::CollectionObject instances in +self+
38
+ # can share Specify::Model::CollectingEvent instances. +false+ otherwise.
39
+ def embedded_collecting_event?
40
+ self[:IsEmbeddedCollectingEvent]
41
+ end
42
+
43
+ # Returns the highest Specify::Model::CollectionObject#catalog_number
44
+ # for collection_objects belonging to +self+.
45
+ def highest_catalog_number
46
+ collection_objects_dataset.max(:CatalogNumber)
47
+ end
48
+
49
+ # Creates a string representation of +self+.
50
+ def inspect
51
+ "#{self} name: #{self.CollectionName}"
52
+ end
53
+
54
+ # Returns a String that is the name of +self+.
55
+ def name
56
+ self[:CollectionName]
57
+ end
58
+
59
+ # Returns the Specify::Model::ViewSetObject that belongs to +self+.
60
+ # The +_collection+ argument will be discared and is only there to allow
61
+ # intances to be used as a Specify::Service::ViewLoader#target.
62
+ def view_set(_collection = nil)
63
+ view_set_dir&.view_set_object
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specify
4
+ module Model
5
+ # CollectionObjects represent the organisms or artifeacts collected, but
6
+ # not the physical items stored in a collection (see
7
+ # Specify::Model::Preparation).
8
+ #
9
+ # A CollectionObject belongs to Specify::Model::Collection and can have one
10
+ # or many #preparations (instances of Specify::Model::Preparation).
11
+ #
12
+ # A CollectionObject belongs to a #collecting_event (an instance of
13
+ # Specify::Model::CollectingEvent), that holds information about when,
14
+ # where, how, and by whom it was collected.
15
+ #
16
+ # A CollectionObject can have one or many #determinations (instances of
17
+ # Specify::Model::Determination), which represent opinions on what
18
+ # Specify::Model::Taxon the CollectionObject represents.
19
+ class CollectionObject < Sequel::Model(:collectionobject)
20
+ include Createable
21
+ include Updateable
22
+
23
+ many_to_one :collection,
24
+ key: :CollectionID
25
+ many_to_one :collection_member,
26
+ class: 'Specify::Model::Collection',
27
+ key: :CollectionMemberID
28
+ many_to_one :accession,
29
+ key: :AccessionID
30
+ many_to_one :cataloger,
31
+ class: 'Specify::Model::Agent',
32
+ key: :CatalogerID
33
+ many_to_one :collecting_event,
34
+ key: :CollectingEventID
35
+ one_to_many :determinations,
36
+ key: :CollectionObjectID
37
+ one_to_many :preparations,
38
+ key: :CollectionObjectID
39
+ many_to_one :created_by,
40
+ class: 'Specify::Model::Agent',
41
+ key: :CreatedByAgentID
42
+ many_to_one :modified_by,
43
+ class: 'Specify::Model::Agent',
44
+ key: :ModifiedByAgentID
45
+
46
+ # Returns the #catalog_number of +self+ if it has one. If not, returns
47
+ # the next available catalog number in the
48
+ # Specify::Model::AutoNumberingScheme in the Specify::Model::Collection
49
+ # +self+ belongs to.
50
+ def auto_number
51
+ catalog_number || collection.auto_numbering_scheme.increment
52
+ end
53
+
54
+ # Sequel hook that assigns a newly created records to a
55
+ # Specify::Model::Collection (the collection is referenced twice; through
56
+ # #collection and #collection_member; the #collection will be
57
+ # automatically set if the records is created through the
58
+ # Specify::Model::Collecion#add_collection_object association method; the
59
+ # hook will set the other reference).
60
+ #
61
+ # Assigns the next available #catalog_number in the collection.
62
+ #
63
+ # Sets the _CatalogedDate_ attribute and assigns a Specify::Model::Agent
64
+ # as the #cataloger.
65
+ #
66
+ # Assigns a GUID.
67
+ #
68
+ # If CollectionObjects in #collection can not share colecting events
69
+ # (there is one Specify::Model::CollectingEvent for every
70
+ # CollectionObject), this will create a new, empty,
71
+ # Specify::Model::CollectingEvent for the record.
72
+ def before_create
73
+ self.collection_member = collection
74
+ self[:CatalogNumber] = auto_number
75
+ self[:CatalogedDate] = Date.today
76
+ self[:CatalogedDatePrecision] = 1
77
+ self[:GUID] = SecureRandom.uuid
78
+ self.collecting_event = embed_collecting_event
79
+ super
80
+ end
81
+
82
+ # Returns a String that is the catalog number of +self+.
83
+ def catalog_number
84
+ self[:CatalogNumber]
85
+ end
86
+
87
+ # Returns a Date that is the date +self+ was cataloged (typically when
88
+ # it was registered in the database).
89
+ def cataloged_date
90
+ self[:CatalogedDate]
91
+ end
92
+
93
+ # If CollectionObjects in #collection can not share colecting events
94
+ # (there is one Specify::Model::CollectingEvent for every
95
+ # CollectionObject), this will create a new, empty,
96
+ # Specify::Model::CollectingEvent for the record.
97
+ def embed_collecting_event
98
+ return unless collection.embedded_collecting_event?
99
+ CollectingEvent.create discipline: collection.discipline
100
+ end
101
+
102
+ # Updates the associated Specify::Model::CollectingEvent with +vals+
103
+ # (a Hash).
104
+ def geo_locate(vals)
105
+ collecting_event.update(vals)
106
+ collecting_event.save
107
+ end
108
+
109
+ # Creates a new Specify::Model::Determination for +self+ with +vals+
110
+ # (a Hash).
111
+ def identify(vals)
112
+ add_determination vals
113
+ self.save
114
+ end
115
+
116
+ # Creates a string representation of +self+.
117
+ def inspect
118
+ to_s
119
+ end
120
+
121
+ # Creates a string representation of +self+.
122
+ def to_s
123
+ "#{catalog_number} cataloged by #{cataloger}, #{cataloged_date}"
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specify
4
+ module Model
5
+ # Creatable is a mixin that provides the standard #before_create hook for
6
+ # Specify::Model classes.
7
+ #
8
+ # Most tables in the _Specify_ schema have a _Version_ (an Integer) that is
9
+ # incremented for each modification and a creation timestamp. The
10
+ # #before_create hook will set these.
11
+ module Createable
12
+ # Initialized the _Version_ to +0+ and sets the creation timestamp of a
13
+ # record.
14
+ def before_create
15
+ self[:Version] = 0
16
+ self[:TimestampCreated] = Time.now
17
+ super
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specify
4
+ module Model
5
+ # Determinations are opinions on what Specify::Model::Taxon a
6
+ # Specify::Model::CollectionObject represents.
7
+ #
8
+ # A Determination belongs to a Specify::Model::CollectionObject
9
+ # (collection_object).
10
+ #
11
+ # A Specify::Model::CollectionObject can have multiple determinations, only
12
+ # one of which can be the _current_ determination.
13
+ #
14
+ # A Determination can belong to a Specify::Model::Taxon. If that taxon
15
+ # is a synonym of another taxon, the Determination will also belong to
16
+ # the accepted Taxon as the preferred_taxon.
17
+ class Determination < Sequel::Model(:determination)
18
+ include Createable
19
+ include Updateable
20
+
21
+ many_to_one :collection,
22
+ key: :CollectionMemberID
23
+ many_to_one :collection_object,
24
+ key: :CollectionObjectID
25
+ many_to_one :taxon,
26
+ key: :TaxonID
27
+ many_to_one :preferred_taxon,
28
+ class: 'Specify::Model::Taxon',
29
+ key: :PreferredTaxonID
30
+ many_to_one :determiner,
31
+ class: 'Specify::Model::Agent',
32
+ key: :DeterminerID
33
+ many_to_one :created_by,
34
+ class: 'Specify::Model::Agent',
35
+ key: :CreatedByAgentID
36
+ many_to_one :modified_by,
37
+ class: 'Specify::Model::Agent',
38
+ key: :ModifiedByAgentID
39
+
40
+ # Sequel hook that assigns a GUID. Sets the collection to the
41
+ # Specify::Model::Collection that the collection_object of +self+
42
+ # belongs to.
43
+ #
44
+ # Sets the preferred_taxon to the Specify::Model::Taxon#accepted_name if
45
+ # it has one, the Specify::Model::Taxon itself otherwise.
46
+ #
47
+ # Sets the _IsCurrent_ status to +true+.
48
+ def before_create
49
+ self[:GUID] = SecureRandom.uuid
50
+ self.collection = collection_object&.collection
51
+ self.preferred_taxon = taxon.accepted_name || taxon
52
+ self[:IsCurrent] = true
53
+ super
54
+ end
55
+
56
+ # Returns +true+ if +self+ is the current determination for
57
+ # #collection_object
58
+ def current?
59
+ self[:IsCurrent]
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specify
4
+ module Model
5
+ # Disciplines are the second lowest level of scope in a Specify::Database.
6
+ #
7
+ # A Discipline belongs to the a Specify::Model::Division.
8
+ #
9
+ # A Discipline has one or more instances of Specify::Model::Collection.
10
+ #
11
+ # A Discipline has one Specify::Model::Taxonomy, and one
12
+ # Specify::Model::Geography (both of which can be shared with other
13
+ # instances of Discipline).
14
+ class Discipline < Sequel::Model(:discipline)
15
+ include Updateable
16
+ many_to_one :division,
17
+ key: :DivisionID
18
+ one_to_many :app_resource_dirs,
19
+ class: 'Specify::Model::AppResourceDir',
20
+ key: :DisciplineID
21
+ one_to_many :collecting_events,
22
+ key: :DisciplineID
23
+ one_to_many :collections,
24
+ key: :DisciplineID
25
+ one_to_many :localities,
26
+ key: :DisciplineID
27
+ many_to_many :auto_numbering_schemes,
28
+ left_key: :DisciplineID,
29
+ right_key: :AutoNumberingSchemeID,
30
+ join_table: :autonumsch_dsp
31
+ many_to_one :taxonomy,
32
+ key: :TaxonTreeDefID
33
+ many_to_one :geography,
34
+ key: :GeographyTreeDefID
35
+ one_to_one :view_set_dir,
36
+ class: 'Specify::Model::AppResourceDir',
37
+ key: :DisciplineID do |ds|
38
+ ds.where(CollectionID: nil,
39
+ UserType: nil,
40
+ IsPersonal: false)
41
+ end
42
+
43
+ # Creates a string representation of +self+.
44
+ def inspect
45
+ "#{self} name: #{self.Name}"
46
+ end
47
+
48
+ # Returns a String that is the name of +self+.
49
+ def name
50
+ self.Name
51
+ end
52
+
53
+ # Returns the Specify::Model::ViewSetObject that belongs to +self+.
54
+ # The +_collection+ argument will be discared and is only there to allow
55
+ # intances to be used as a Specify::Service::ViewLoader#target.
56
+ def view_set(_collection = nil)
57
+ view_set_dir&.view_set_object
58
+ end
59
+ end
60
+ end
61
+ end