diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..2431b1a --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,60 @@ +# Sample workflow for building and deploying a Jekyll site to GitHub Pages +name: Deploy Jekyll with GitHub Pages dependencies preinstalled +on: + # Runs on pushes targeting the default branch + push: + branches: ["main", "feat/yard", "**doc**"] + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0.2 # This is the Ruby version of DRKZ's Levante + - name: Install dependencies + run: | + gem install bundler + bundle install + - name: Generate YARD documentation + run: | + gem install yard + yard doc + - name: Build with Jekyll + uses: actions/jekyll-build-pages@v1 + with: + source: ./doc + destination: ./_site + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + artifact-name: site + path: _site + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index d0ecee6..2976ec8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,67 @@ lib/ruby/gems .paths build bin/ncn +# Created by https://www.toptal.com/developers/gitignore/api/ruby +# Edit at https://www.toptal.com/developers/gitignore?templates=ruby + +### Ruby ### +*.gem +*.rbc +/.config +/coverage/ +/InstalledFiles +/pkg/ +/spec/reports/ +/spec/examples.txt +/test/tmp/ +/test/version_tmp/ +/tmp/ + +# Used by dotenv library to load environment variables. +# .env + +# Ignore Byebug command history file. +.byebug_history + +## Specific to RubyMotion: +.dat* +.repl_history +build/ +*.bridgesupport +build-iPhoneOS/ +build-iPhoneSimulator/ + +## Specific to RubyMotion (use of CocoaPods): +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# vendor/Pods/ + +## Documentation cache and generated files: +/.yardoc/ +/_yardoc/ +/doc/ +/rdoc/ + +## Environment normalization: +/.bundle/ +/vendor/bundle +/lib/bundler/man/ + +# for a library or gem, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# Gemfile.lock +# .ruby-version +# .ruby-gemset + +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: +.rvmrc + +# Used by RuboCop. Remote config files pulled in from inherit_from directive. +# .rubocop-https?--* + +# End of https://www.toptal.com/developers/gitignore/api/ruby + +.direnv/ +.envrc diff --git a/lib/fesom_possible_var.rb b/lib/fesom_possible_var.rb index 13f0aeb..eb08dea 100644 --- a/lib/fesom_possible_var.rb +++ b/lib/fesom_possible_var.rb @@ -12,6 +12,23 @@ def initialize(variable_id, unit, description, time_method) end + # Generates a collection of FesomPossibleVar objects based upon a FORTRAN code snippet + # + # Maps each line of the argument [String] code via a regex based upon the initialization of + # this class, using attributes , , and . + # + # Special handling of the variable "tso", which uses TimeMethods::POINT instead of the + # default TimeMethods::Mean + # + # TODO(PG -- Reverse Engineering): I still need to find out of the regex **needs** the parameters + # or if instead it is used to **figure out what values they should have for initialization**. + # + # NOTE(PG -- Reverse Engineering): This looks like the Ruby equivalent of a Python `classmethod` + # and seems to implement an alternative way of constructing objects of this class. + # + # @param code [String] `FORTRAN` code to pare + # @param sort [Boolean] Whether or not to return the variables sorted (alphabetically?) by `variable_id`. + # @return [Array] An array of FesomPossibleVar objects def self.create_from_fortran_code(code, sort: true) vars = code.split("\n").map do |init_line| /.+?, ['"](?[^,]+?)['"], ['"](?.+?)['"], ['"](?[^,]+?)['"]\) *.*/ =~ init_line @@ -30,7 +47,8 @@ def self.create_from_fortran_code(code, sort: true) end end - + # Helper method to nicely print out this FesomPossibleVar. + # @return [String] def to_s "#{@variable_id}: '#{@unit}' #{@time_method} '#{@description}'" end diff --git a/lib/steps_chain.rb b/lib/steps_chain.rb index e2e5ca1..930394e 100644 --- a/lib/steps_chain.rb +++ b/lib/steps_chain.rb @@ -1,9 +1,20 @@ module CMORizer + # The StepsChain class manages the sequence of processing steps for converting + # FESOM variable data to CMOR-compliant format. It initializes the necessary steps, + # handles the execution of these steps, and manages the metadata required for the process. class StepsChain attr_reader :input_variable_name, :input_frequency_name - - # fesom_variable_description: "fesom name"_"available frequency" - # cmor_variable_description: "variable_id"_"CMIP table_id" + + # Initializes a StepsChain instance. + # + # This constructor sets up the processing chain for converting FESOM variable data to CMOR-compliant format. + # It parses the provided descriptions for FESOM and CMOR variables, initializes the steps from a given block + # or default step classes, and prepares the chain for execution. + # + # @param default_step_classes [Array] Default classes for processing steps if no specific steps are provided. + # @param fesom_variable_description [String] Description of the FESOM variable in the format "variable_name_frequency". + # @param cmor_variable_description [String] Description of the CMOR variable in the format "variable_id_table_id". + # @param block [Proc] An optional block to customize the processing steps. def initialize(default_step_classes, fesom_variable_description, cmor_variable_description, &block) @input_variable_name, @input_frequency_name = fesom_variable_description.split('_') @cmor_variable_id, @cmor_table_id = cmor_variable_description.split('_') @@ -16,12 +27,21 @@ def initialize(default_step_classes, fesom_variable_description, cmor_variable_d @step_classes = default_step_classes if @step_classes.empty? end - + # Returns a string representation of the steps chain. + # + # @return [String] A string in the format "input_variable_input_frequency ==> cmor_variable_id_cmor_table_id". def to_s "#{@input_variable_name}_#{@input_frequency_name} ==> #{@cmor_variable_id}_#{@cmor_table_id}" end - + + # Executes the processing steps on the provided FESOM files. + # + # @param fesom_files [Array] List of FESOM files to process. + # @param experiment [Experiment] The experiment metadata. + # @param data_request [DataRequest] The data request metadata. + # @param grid_description_file [String] The grid description file path. + # @param version_date [String] The version date for the output files. def execute(fesom_files, experiment, data_request, grid_description_file, version_date) return if @step_classes.empty? @@ -95,6 +115,17 @@ def execute(fesom_files, experiment, data_request, grid_description_file, versio end + # Creates global attributes for the output files. + # + # @param experiment [Experiment] The experiment metadata. + # @param first_file_year [Integer] The year of the first file. + # @param last_file_year [Integer] The year of the last file. + # @param variable_id [String] The variable ID. + # @param frequency [String] The frequency of the data. + # @param table_id [String] The CMIP table ID. + # @param realms [Array] The realms associated with the variable. + # @param version_date [String] The version date for the output files. + # @return [GlobalAttributes] The global attributes for the output files. private def create_global_attributes(experiment:, first_file_year:, last_file_year:, variable_id:, frequency:, table_id:, realms:, version_date:) builder = GlobalAttributesBuilder.new builder.set_experiment_info(id: experiment.experiment_id, @@ -120,12 +151,19 @@ def execute(fesom_files, experiment, data_request, grid_description_file, versio end + # Adds a processing step to the steps chain. + # + # @param sym [Symbol] The symbol representing the step class. private def add_step(sym) cls = CMORizer::Step.const_get sym @step_classes << cls end - + # Handles undefined methods to add steps to the chain. + # + # @param method_sym [Symbol] The name of the undefined method. + # @param args [Array] The arguments passed to the undefined method. + # @param block [Proc] An optional block passed to the undefined method. def method_missing(method_sym, *args, &block) return super unless @eval_mode # we assume every unknown method designates a sub-task diff --git a/lib/version.rb b/lib/version.rb index f6d9b25..4d4b394 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,7 @@ module Seamore - VERSION = '2.1.1' # version number according to semantic versioning (SemVer) paradigm + # The current version of the Seamore library following the semantic + # versioning (SemVer) paradigm. + # + # @return [String] the current version of the Seamore library. + VERSION = '2.1.1' end