<commit_before>module Tint
	module Input
		def self.multiple_select_options(site, key)
			site.config.dig("options", key)
		end

		def self.type(key, value, site)
			return unless scalarish?(value)

			if [true, false].include? value
				:checkbox
			elsif key.to_s.end_with?("_path") || key.to_s.end_with?("_paths")
				:file
			elsif key.to_s.downcase.end_with?("_datetime") || key.to_s.downcase == "datetime" || value.is_a?(Time)
				:datetime
			elsif key.to_s.downcase.end_with?("_date") || key.to_s.downcase == "date"
				:date
			elsif value.is_a?(String) && value.length > 50
				:textarea
			elsif multiple_select_options(site, key)
				:multiple_select
			elsif key && site.config.dig("options", ActiveSupport::Inflector.pluralize(key))
				:select
			else
				:text
			end
		end

		def self.scalarish?(value)
			!value.is_a?(Enumerable) || (value.is_a?(Array) && value.map { |v| !value.is_a?(Enumerable) })
		end

		def self.build(key, name, value, site, type=nil)
			type ||= Input.type(key, value, site)
			class_for(type).new(key, name, value, site)
		end

		def self.class_for(type)
			{
				file: File,
				checkbox: Checkbox,
				datetime: DateTime,
				date: Date,
				textarea: Textarea,
				multiple_select: MultipleSelect,
				select: Select,
				text: Text
			}.fetch(type)
		end

		class Base
			attr_reader :key, :name, :value, :site

			def initialize(key, name, value, site)
				@key = key
				@name = name
				@value = value
				@site = site
			end

			def render
				Slim::Template.new("app/views/inputs/#{template}.slim").render(self)
			end
		end

		class Checkbox < Base
			def template
				:checkbox
			end
		end

		class File < Base
			def file
				Tint::File.new(site, value)
			end

			def encoded_image
				file.encoded_image
			end

			def template
				:file
			end
		end

		class DateTime < Base
			def time
				Time.parse(value.to_s) if value.to_s != ""
			end

			def template
				:datetime
			end
		end

		class Date < Base
			def date
				::Date.parse(value.to_s) if value.to_s != ""
			end

			def template
				:date
			end
		end

		class Textarea < Base
			def template
				:textarea
			end
		end

		class Select < Base
			def options
				format_options(site.config.dig("options", ActiveSupport::Inflector.pluralize(key)))
			end

			def template
				:select
			end

		protected

			def format_options(options)
				if options.is_a? Array
					options.map { |value| [value, value] }
				elsif options.is_a? Hash
					options.map { |value, display| [value, display] }
				else
					fail ArgumentError, "options must be a Hash or an Array"
				end
			end
		end

		class MultipleSelect < Select
			def value
				Array(@value)
			end

			def options
				format_options(Input.multiple_select_options(site, key))
			end

			def template
				:multiple_select
			end
		end

		class Text < Base
			def template
				:text
			end
		end
	end
end
<commit_msg>Always get select options the same way.<commit_after>module Tint
	module Input
		def self.select_options(site, key)
			site.config.dig("options", key)
		end

		def self.type(key, value, site)
			return unless scalarish?(value)

			if [true, false].include? value
				:checkbox
			elsif key.to_s.end_with?("_path") || key.to_s.end_with?("_paths")
				:file
			elsif key.to_s.downcase.end_with?("_datetime") || key.to_s.downcase == "datetime" || value.is_a?(Time)
				:datetime
			elsif key.to_s.downcase.end_with?("_date") || key.to_s.downcase == "date"
				:date
			elsif value.is_a?(String) && value.length > 50
				:textarea
			elsif select_options(site, key)
				:multiple_select
			elsif select_options(site, ActiveSupport::Inflector.pluralize(key))
				:select
			else
				:text
			end
		end

		def self.scalarish?(value)
			!value.is_a?(Enumerable) || (value.is_a?(Array) && value.map { |v| !value.is_a?(Enumerable) })
		end

		def self.build(key, name, value, site, type=nil)
			type ||= Input.type(key, value, site)
			class_for(type).new(key, name, value, site)
		end

		def self.class_for(type)
			{
				file: File,
				checkbox: Checkbox,
				datetime: DateTime,
				date: Date,
				textarea: Textarea,
				multiple_select: MultipleSelect,
				select: Select,
				text: Text
			}.fetch(type)
		end

		class Base
			attr_reader :key, :name, :value, :site

			def initialize(key, name, value, site)
				@key = key
				@name = name
				@value = value
				@site = site
			end

			def render
				Slim::Template.new("app/views/inputs/#{template}.slim").render(self)
			end
		end

		class Checkbox < Base
			def template
				:checkbox
			end
		end

		class File < Base
			def file
				Tint::File.new(site, value)
			end

			def encoded_image
				file.encoded_image
			end

			def template
				:file
			end
		end

		class DateTime < Base
			def time
				Time.parse(value.to_s) if value.to_s != ""
			end

			def template
				:datetime
			end
		end

		class Date < Base
			def date
				::Date.parse(value.to_s) if value.to_s != ""
			end

			def template
				:date
			end
		end

		class Textarea < Base
			def template
				:textarea
			end
		end

		class Select < Base
			def options
				format_options(Input.select_options(site, ActiveSupport::Inflector.pluralize(key)))
			end

			def template
				:select
			end

		protected

			def format_options(options)
				if options.is_a? Array
					options.map { |value| [value, value] }
				elsif options.is_a? Hash
					options.map { |value, display| [value, display] }
				else
					fail ArgumentError, "options must be a Hash or an Array"
				end
			end
		end

		class MultipleSelect < Select
			def value
				Array(@value)
			end

			def options
				format_options(Input.select_options(site, key))
			end

			def template
				:multiple_select
			end
		end

		class Text < Base
			def template
				:text
			end
		end
	end
end

{'fraction_non_alphanumeric': 0.10929909784871616, 'fraction_numerical': 0.0006939625260235947, 'mean_word_length': 2.7508132726089785, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6832576', 'n_tokens_mistral': 2576, 'n_tokens_neox': 1994, 'n_words': 517}