JonTheNiceGuy
JonTheNiceGuy

Reputation: 641

How do I determine what the data type is of a value in Ruby?

I'm using Jekyll, and have stored some information in _data/some_data.yml, which contains data like this:

---
links:
- http://example.org/some/data
- http://example.org/some/other/data

Another record, _data/more_data.yml, contains data like this:

---
links: http://example.com

A third record, _data/yet_more_data.yml, contains data like this:

---
links:
  "A title-based link": http://example.net
  "Another title-based link": https://example.net/some/other/page

I will be parsing the data sources in the template, like this:

<pre>
{% for a_record in site.data %}
  Parsing: {{ a_record[0] }}
  Links: 
    << PSUDOCODE >>
      {% if a_record[1].links is a string %}
        * [{{ a_record[1].links }}]({{ a_record[1].links }})
      {% elseif a_record[1].links is an array %}
        {% for link in a_record[1].links %}
          * [{{ link }}]({{ link }}]
        {% endfor %}
      {% elseif a_record[1].links is a hash %}
        {% for link in a_record[1].links %}
          * [{{ link[0] }}]({{ link[1] }})
        {% endfor %}
      {% endif %}
    << /PSUDOCODE >>
  - End Record -
{% endfor %}
</pre>

How can I work out if I'm looking at a string, an array or a hash?

I started writing a plugin to support this check, but it's not working out the way I expected - at all!

module Jekyll
  module IsAFilter
    def is_a_string(value)
      if not value.instance_of?(::Hash) 
        if not value.instance_of?(::Array)
          if value.instance_of?(::String)
            return true
          end
        end
      end
      return false
    end
    def is_a_hash(value)
      if not value.instance_of?(::Array)
        if value.instance_of?(::Hash)
          return true
        end
      end
      return false
    end
    def is_an_array(value)
      if not value.instance_of?(::Hash)
        if value.instance_of?(::Array)
          return true
        end
      end
      return false
    end
  end
end

Liquid::Template.register_filter(Jekyll::IsAFilter)

To use that, I imagined that I could do {% if a_record[1].links | is_a_string %}{{ a_record[1].links }}{% endif %} but that always renders it as a string, even if it's an array or a hash?

And, before it's suggested, yes, I could say "you must always use the YAML hash format", but once I've finished writing this, I'm going to be handing control of the data to someone else, so I want to be sure that whatever they end up putting in there, it'll work.

Upvotes: 0

Views: 128

Answers (2)

JonTheNiceGuy
JonTheNiceGuy

Reputation: 641

I had it so close! Thanks to @bashford7's answer, I amended my code to use the form value.is_a? String, but the problem was actually in my understanding of Jekyll...

I had to use this stanza:

{% assign check_variable = some_variable | some_filter_that_returns_true %}
{% if check_variable %}
USE THIS STANZA - IT WORKS
{% endif %}

Instead of what I assumed I could use, which was this stanza:

{% if some_variable | some_filter_that_returns_true %}
DON'T USE THIS STANZA - IT DOESN'T WORK
{% endif %}

My final plugin, if it's useful, looks like this:

module Jekyll
  module IsAFilters
    def is_a(value)
      return value.inspect
    end
    def is_a_string(value)
      if value.is_a? String
        return true
      end
      return false
    end
    def is_a_hash(value)
      if value.is_a? Hash
        return true
      end
      return false
    end
    def is_an_array(value)
      if value.is_a? Array
        return true
      end
      return false
    end
  end
end

Liquid::Template.register_filter(Jekyll::IsAFilters)

Upvotes: 0

kykyi
kykyi

Reputation: 385

In ruby you can use .is_a? DataType. E.g.

[1] pry(main)> "hello".is_a? String
=> true
[2] pry(main)> {key: 1}.is_a? Hash
=> true
[3] pry(main)> [1,2,3].is_a? Array
=> true

Upvotes: 1

Related Questions