specify_cli 0.0.5

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