From 8e8cfa6c52ff8fc2a655b768db5baafed40c1a2d Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Tue, 19 Sep 2017 15:20:01 +0200 Subject: Add `ModelAttribute` This new class will allow us to generate a list of all editable fields in all our models including the type of each field. We need this for Compliance Control, in order to get a list of fields or models & fields that can be selected to validate a given model validation check. The crucial bits here are the models, fields, and the types of those fields. These need to be defined (manually at least to begin with), accessible, and filterable. Refs #4401 --- lib/model_attribute.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 lib/model_attribute.rb (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb new file mode 100644 index 000000000..be5caea94 --- /dev/null +++ b/lib/model_attribute.rb @@ -0,0 +1,17 @@ +class ModelAttribute + cattr_reader :all + + @@all = [] + + attr_reader :klass, :name, :data_type + + def self.define(klass, name, data_type) + @@all << new(klass, name, data_type) + end + + def initialize(klass, name, data_type) + @klass = klass + @name = name + @data_type = data_type + end +end -- cgit v1.2.3 From 2f555897bff3f8fa6dd5e9e0c6d48f0073edc349 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Tue, 19 Sep 2017 15:39:37 +0200 Subject: ModelAttribute spec: Allow test to handle existing elements in `@@all` When `ModelAttribute` instances are added to `@@all` directly in the class, the test breaks. Make it a little more robust by checking change in array size instead of total size. Refs #4401 --- lib/model_attribute.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index be5caea94..b1297d43d 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -14,4 +14,6 @@ class ModelAttribute @name = name @data_type = data_type end + + define :journey_pattern, :name, :string end -- cgit v1.2.3 From 30fc0d3f1a9a158a0d45bbaf2f78e176f74ac943 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Tue, 19 Sep 2017 16:46:22 +0200 Subject: ModelAttribute: Add `ModelAttribute`s for a bunch of models&attributes We want to define `ModelAttribute`s for an initial set of `Chouette` models: * Chouette::Route * Chouette::JourneyPattern * Chouette::VehicleJourney * Chouette::Footnote * Chouette::TimeTable * Chouette::RoutingConstraintZone I added these by looking at the `schema.rb` as well as some form views for these models. Given that information, I made some guesses about what attributes it might make sense to add here. We want to end up with a collection of only editable attributes for these models, so this excludes things like `created_at`, foreign keys, and programmatically set fields. This is my guess at what those fields are. We can refine the list later. We'll be using this list for Compliance Control to get a set of fields of a given type in order to create custom validations using those fields. Refs #4401 --- lib/model_attribute.rb | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index b1297d43d..081d0cd0f 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -15,5 +15,44 @@ class ModelAttribute @data_type = data_type end + # Chouette::Route + define :route, :name, :string + define :route, :published_name, :string + define :route, :comment, :string + define :route, :number, :string + define :route, :direction, :string + define :route, :wayback, :string + + # Chouette::JourneyPattern define :journey_pattern, :name, :string + define :journey_pattern, :published_name, :string + define :journey_pattern, :comment, :string + define :journey_pattern, :registration_number, :string + define :journey_pattern, :section_status, :integer + + # Chouette::VehicleJourney + define :vehicle_journey, :comment, :string + define :vehicle_journey, :status_value, :string + define :vehicle_journey, :transport_mode, :string + define :vehicle_journey, :facility, :string + define :vehicle_journey, :published_journey_name, :string + define :vehicle_journey, :published_journey_identifier, :string + define :vehicle_journey, :vehicle_type_identifier, :string + define :vehicle_journey, :number, :integer + define :vehicle_journey, :mobility_restricted_suitability, :boolean + define :vehicle_journey, :flexible_service, :boolean + + # Chouette::Footnote + define :footnote, :code, :string + define :footnote, :label, :string + + # Chouette::TimeTable + define :time_table, :version, :string + define :time_table, :comment, :string + define :time_table, :start_date, :date + define :time_table, :end_date, :date + define :time_table, :color, :string + + # Chouette::RoutingConstraintZone + define :routing_constraint_zone, :name, :string end -- cgit v1.2.3 From e1547b52a372942b34cda3b3fee4ab76e9f1b65e Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Tue, 19 Sep 2017 16:59:45 +0200 Subject: ModelAttribute: Add `#code` method A method that returns a string representation of the attribute, in the form `:class#:name". This will be used to store a reference to the attribute in the database. For example, a validation will reference a `ModelAttribute` in a database column using this `#code` string. Refs #4401 --- lib/model_attribute.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index 081d0cd0f..22c366b37 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -55,4 +55,8 @@ class ModelAttribute # Chouette::RoutingConstraintZone define :routing_constraint_zone, :name, :string + + def code + "#{@klass}##{@name}" + end end -- cgit v1.2.3 From c9a997f337c9b45f62b50629de96fa95f20c1a7f Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Tue, 19 Sep 2017 17:58:08 +0200 Subject: ModelAttribute: Make `@@all` a class instance variable Robert argues that the class variable is not ideal because its value gets shared with subclasses, violating the Liskov substitution principle: 17:44:23 < robert> ```133] pry(main)> class A; @@greeting = :hello end 17:44:23 < robert> => :hello 17:44:23 < robert> [134] pry(main)> class B < A; end 17:44:23 < robert> => nil 17:44:23 < robert> [135] pry(main)> B.class_variable_get '@@greeting' 17:44:23 < robert> => :hello Instead, go with his suggestion to use a class instance variable instead, which gives us the same amount of availability of the `all` list while not sharing it indiscriminately and making it easier to test. Refs #4401 --- lib/model_attribute.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index 22c366b37..98bb54b67 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -1,12 +1,12 @@ class ModelAttribute - cattr_reader :all - - @@all = [] - attr_reader :klass, :name, :data_type + def self.all + @__all__ ||= [] + end + def self.define(klass, name, data_type) - @@all << new(klass, name, data_type) + all << new(klass, name, data_type) end def initialize(klass, name, data_type) -- cgit v1.2.3 From a60bf813aa118648998093242d6db0e1d8613e76 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Tue, 19 Sep 2017 18:13:20 +0200 Subject: ModelAttribute: Add `.methods_by_class` method Allows us to get all `ModelAttribute`s given a certain class name. Needed an `#==` method to be able to test object equality more easily so I added one in. I don't like that the `klass` is a lowercase symbol and the `klass` attribute to `.methods_by_class` is a constantized string. Want to correct that and make them uniform. Only did it this way because that's how it was suggested in the ticket. Refs #4401 --- lib/model_attribute.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index 98bb54b67..8f1ecabed 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -9,6 +9,12 @@ class ModelAttribute all << new(klass, name, data_type) end + def self.methods_by_class(klass) + all.select do |model_attr| + model_attr.klass == klass.downcase.to_sym + end + end + def initialize(klass, name, data_type) @klass = klass @name = name @@ -59,4 +65,10 @@ class ModelAttribute def code "#{@klass}##{@name}" end + + def ==(other) + klass == other.klass && + name == other.name && + data_type == other.data_type + end end -- cgit v1.2.3 From 5b437302c3cbc90f920de11169f249658c23a5ee Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Tue, 19 Sep 2017 18:16:16 +0200 Subject: ModelAttribute.methods_by_class: Take symbol parameter instead of string Didn't like how `#initialize` takes a different type for `klass` than `.methods_by_class`. Make these types and values uniform. If we need to change it, we should make a separate mechanism to do so. I think. Refs #4401 --- lib/model_attribute.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index 8f1ecabed..84706ba4d 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -11,7 +11,7 @@ class ModelAttribute def self.methods_by_class(klass) all.select do |model_attr| - model_attr.klass == klass.downcase.to_sym + model_attr.klass == klass end end -- cgit v1.2.3 From 9179af1df905ff9980228d2aa0ba77418f2781aa Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Fri, 22 Sep 2017 12:11:41 +0200 Subject: ModelAttribute: Add `.methods_by_class_and_type` method This enables filtering by class like `.methods_by_class` and additionally only selecting attributes matching a certain data type. Refs #4401 --- lib/model_attribute.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index 84706ba4d..e74dd1060 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -15,6 +15,12 @@ class ModelAttribute end end + def self.methods_by_class_and_type(klass, type) + methods_by_class(klass).select do |model_attr| + model_attr.data_type == type + end + end + def initialize(klass, name, data_type) @klass = klass @name = name -- cgit v1.2.3 From 404b143af9ed49912e1e0065c832639188aa87de Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Fri, 22 Sep 2017 12:25:36 +0200 Subject: ModelAttribute: Add `.classes` method This allows people to get a list of the classes defined in `ModelAttribute`. The classes are turned into constant-cased strings. Not sure if that's useful, but this is how it was described in the ticket. Refs #4401 --- lib/model_attribute.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index e74dd1060..53c0b7a46 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -9,6 +9,14 @@ class ModelAttribute all << new(klass, name, data_type) end + def self.classes + all + .map(&:klass) + .map(&:to_s) + .map(&:camelize) + .uniq + end + def self.methods_by_class(klass) all.select do |model_attr| model_attr.klass == klass -- cgit v1.2.3 From 9086e4c7d253927e7fad07bcd4eb194eeff393ca Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Fri, 22 Sep 2017 12:42:41 +0200 Subject: ModelAttribute: Add `.group_by_class` method This returns all defined `ModelAttribute`s as a hash of class keys containing lists of the attributes they contain. Refs #4401 --- lib/model_attribute.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index 53c0b7a46..78c9168eb 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -17,6 +17,10 @@ class ModelAttribute .uniq end + def self.group_by_class + all.group_by(&:klass) + end + def self.methods_by_class(klass) all.select do |model_attr| model_attr.klass == klass -- cgit v1.2.3 From 2d7ce83439f29d261f0c5ec05140359218cfe661 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Fri, 22 Sep 2017 14:10:45 +0200 Subject: ModelAttribute: Add `#from_code` method Enables finding a `ModelAttribute` by a string code combining klass and name. Refs #4401 --- lib/model_attribute.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib/model_attribute.rb') diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb index 78c9168eb..60580e306 100644 --- a/lib/model_attribute.rb +++ b/lib/model_attribute.rb @@ -21,6 +21,14 @@ class ModelAttribute all.group_by(&:klass) end + def self.from_code(code) + klass, name = code.split('#').map(&:to_sym) + + methods_by_class(klass).select do |model_attr| + model_attr.name == name + end.first + end + def self.methods_by_class(klass) all.select do |model_attr| model_attr.klass == klass -- cgit v1.2.3