sumoheavy / jira-ruby

A Ruby gem for the JIRA REST API
MIT License
654 stars 412 forks source link

Update `client.Field.map_fields` to produce more idomatic ruby method names from attributes #428

Open jcouball opened 6 months ago

jcouball commented 6 months ago

The existing implementation will create method names that have capital letters or multiple underscores in a row. See an example in the code comments below.

Consider using the below implementation.

This would be a backward incompatible change for users who depend on the existing client.Field.map_fields behavior.

I wanted to make a note of my code here but didn't have time for a full PR with tests. Figured I'd make a note of it here and get feedback before investing in tests.

module JIRA
  # Extension to Jira resources
  module Resource
    # Extend the JIRA::Resource::Field class to map custom fields to a method name
    # using active support camelize
    class Field < JIRA::Base
      # Translate a custom field description to a underscore-case, method-safe name
      #
      # Enable this field translation by calling `client.Field.map_fields`.
      #
      # This enables use of this safe name in the following places:
      #
      # * As the method names for accessing the custom field value on the resource
      #
      #   ```ruby
      #   # For custom issue field whose id is 'customfield_13806' and whose
      #   # name is 'Target start'
      #   issue = client.Issue.find('PDT-123')
      #   issue.customfield_13806 #=> "2021-01-01"
      #   issue.target_start #=> "2021-01-01"
      #   ```
      #
      # * As names of fields to return from a JQL query
      #
      #   For custom issue field whose id is 'customfield_13806' and whose
      #   # name is 'Target start':
      #
      #   ```ruby
      #   query_string = 'project = PDT'
      #   client.Issue.jql(query_string, fields: %w[key target_start])
      #   ```
      #
      #   **Note** that field names in the query string must use the field name, not
      #   the method name.
      #
      #   ```ruby
      #   query_string = "project = PDT AND 'Target start' > '2021-01-01'"
      #
      #   # or
      #   target_start_field = client.Field.find('customfield_13806').name #=> "Target start"
      #   query_string = "project = PDT AND '#{target_start_field}' > '2021-01-01'"
      #
      #   client.Issue.jql(query_string, fields: %w[key target_start])
      #   ```
      #
      # * As a safe field name can NOT be used when creating an issue
      #
      #   ```ruby
      #   fields = {
      #     project: { key: 'PDT' },
      #     summary: 'Test issue',
      #     issuetype: { name: 'Epic' },
      #     customfield_13806: '2021-01-01',
      #     description: 'This is a test issue'
      #   }
      #   issue = client.Issue.build
      #   issue.save!({ fields: fields })
      #   ```
      #
      # * As a safe field name can NOT be used when updating an issue
      #
      #   ```ruby
      #   issue = client.Issue.find('PDT-1')
      #   issue.save!({ fields: { customfield_13806: '2025-06-01' } })
      #   ```
      #
      def self.safe_name(description)
        description.downcase.tap do |name|
          name.gsub!(/\s+|[^\w]+/, '_') # Replace spaces and non-word characters with underscores
          name.gsub!(/^_+|_+$/, '') # Remove leading and trailing underscores
          name.gsub!(/_+/, '_') # Replace multiple underscores with a single underscore
        end
      end
    end
  end
end