<commit_before>class Kumogata::Client
  def initialize(options)
    @options = options
    @options = Hashie::Mash.new(@options) unless @options.kind_of?(Hashie::Mash)
    @cloud_formation = AWS::CloudFormation.new
  end

  def create(path_or_url, stack_name = nil)
    @options.delete_stack = false if stack_name
    template = open_template(path_or_url)

    if @options.delete_stack?
      template['Resources'].each do |k, v|
        v['DeletionPolicy'] = 'Retain'
      end
    end

    create_stack(template, stack_name)
    nil
  end

  def validate(path_or_url)
    template = open_template(path_or_url)
    validate_template(template)
    nil
  end

  def convert(path_or_url)
    template = open_template(path_or_url)

    if ruby_template?(path_or_url)
      JSON.pretty_generate(template)
    else
      devaluate_template(template).chomp
    end
  end

  def update(path_or_url, stack_name)
    template = open(path_or_url) do |f|
      evaluate_template(f)
    end

    update_stack(template, stack_name)
    nil
  end

  def delete(stack_name)
    if @options.force? or agree("Are you sure you want to delete `#{stack_name}`? ".yellow)
      delete_stack(stack_name)
    end

    nil
  end

  def list(stack_name = nil)
    stacks = describe_stacks(stack_name)
    JSON.pretty_generate(stacks)
  end

  def export(stack_name)
    template = export_template(stack_name)
    devaluate_template(template).chomp
  end

  def show_outputs(stack_name)
    outputs = describe_outputs(stack_name)
    JSON.pretty_generate(outputs)
  end

  def show_resources(stack_name)
    resources = describe_resources(stack_name)
    JSON.pretty_generate(resources)
  end

  private ###########################################################

  def open_template(path_or_url)
    open(path_or_url) do |f|
      if ruby_template?(path_or_url)
        evaluate_template(f)
      else
        JSON.parse(f.read)
      end
    end
  end

  def ruby_template?(path_or_url)
    File.extname(path_or_url) == '.rb'
  end

  def evaluate_template(template)
    key_converter = proc do |key|
      key = key.to_s
      key.gsub!('__', '::') if @options.replace_underscore?
      key
    end

    value_converter = proc do |v|
      case v
      when Hash, Array
        v
      else
        v.to_s
      end
    end

    Dslh.eval(template.read, {
      :key_conv   => key_converter,
      :value_conv => value_converter,
      :scope_hook => method(:define_template_func),
      :filename   => template.path,
    })
  end

  def devaluate_template(template)
    exclude_key = proc do |k|
      k = k.to_s.gsub('::', '__')
      k !~ /\A[_a-z]\w+\Z/i and k !~ %r|\A/\S*\Z|
    end

    key_conv = proc do |k|
      k = k.to_s

      if k =~ %r|\A/\S*\Z|
        proc do |v, nested|
          if nested
            "_path(#{k.inspect}) #{v}"
          else
            "_path #{k.inspect}, #{v}"
          end
        end
      else
        k.gsub('::', '__')
      end
    end

    value_conv = proc do |v|
      if v.kind_of?(String) and v =~ /\A(?:0|[1-9]\d*)\Z/
        v.to_i
      else
        v
      end
    end

    Dslh.deval(template, :key_conv => key_conv, :value_conv => value_conv, :exclude_key => exclude_key)
  end

  def define_template_func(scope)
    scope.instance_eval(<<-'EOS')
      def _join(data, options = {})
        options = {
          :undent    => true,
          :trim_mode => nil,
        }.merge(options)

        data = data.undent if options[:undent]

        @__refs__ = []
        def Ref(value); @__refs__ << {"Ref" => value}; "\0"; end
        data = ERB.new(data, nil, options[:trim_mode]).result(binding)
        undef Ref

        data = data.split("\0").zip(@__refs__)
        @__refs__ = nil

        data = data.flatten.select {|i| not i.nil? }.map {|i|
          if i.kind_of?(String)
            StringIO.new(i).to_a
          else
            i
          end
        }.flatten

        return {
          'Fn::Join' => ['', data]
        }
      end

      def _path(path, value = nil, &block)
        if block
          value = Dslh::ScopeBlock.nest(binding, 'block')
        end

        @__hash__[path] = value
      end<commit_msg>Small fix<commit_after>class Kumogata::Client
  def initialize(options)
    @options = options
    @options = Hashie::Mash.new(@options) unless @options.kind_of?(Hashie::Mash)
    @cloud_formation = AWS::CloudFormation.new
  end

  def create(path_or_url, stack_name = nil)
    @options.delete_stack = false if stack_name
    template = open_template(path_or_url)

    if @options.delete_stack?
      template['Resources'].each do |k, v|
        v['DeletionPolicy'] = 'Retain'
      end
    end

    create_stack(template, stack_name)
    nil
  end

  def validate(path_or_url)
    template = open_template(path_or_url)
    validate_template(template)
    nil
  end

  def convert(path_or_url)
    template = open_template(path_or_url)

    if ruby_template?(path_or_url)
      JSON.pretty_generate(template)
    else
      devaluate_template(template).chomp
    end
  end

  def update(path_or_url, stack_name)
    template = open(path_or_url) do |f|
      evaluate_template(f)
    end

    update_stack(template, stack_name)
    nil
  end

  def delete(stack_name)
    if @options.force? or agree("Are you sure you want to delete `#{stack_name}`? ".yellow)
      delete_stack(stack_name)
    end

    nil
  end

  def list(stack_name = nil)
    stacks = describe_stacks(stack_name)
    JSON.pretty_generate(stacks)
  end

  def export(stack_name)
    template = export_template(stack_name)
    devaluate_template(template).chomp
  end

  def show_outputs(stack_name)
    outputs = describe_outputs(stack_name)
    JSON.pretty_generate(outputs)
  end

  def show_resources(stack_name)
    resources = describe_resources(stack_name)
    JSON.pretty_generate(resources)
  end

  private ###########################################################

  def open_template(path_or_url)
    open(path_or_url) do |f|
      if ruby_template?(path_or_url)
        evaluate_template(f)
      else
        JSON.parse(f.read)
      end
    end
  end

  def ruby_template?(path_or_url)
    File.extname(path_or_url) == '.rb'
  end

  def evaluate_template(template)
    key_converter = proc do |key|
      key = key.to_s
      key.gsub!('__', '::') if @options.replace_underscore?
      key
    end

    value_converter = proc do |v|
      case v
      when Hash, Array
        v
      else
        v.to_s
      end
    end

    Dslh.eval(template.read, {
      :key_conv   => key_converter,
      :value_conv => value_converter,
      :scope_hook => method(:define_template_func),
      :filename   => template.path,
    })
  end

  def devaluate_template(template)
    exclude_key = proc do |k|
      k = k.to_s.gsub('::', '__')
      k !~ /\A[_a-z]\w+\Z/i and k !~ %r|\A/\S*\Z|
    end

    key_conv = proc do |k|
      k = k.to_s

      if k =~ %r|\A/\S*\Z|
        proc do |v, nested|
          if nested
            "_path(#{k.inspect}) #{v}"
          else
            "_path #{k.inspect}, #{v}"
          end
        end
      else
        k.gsub('::', '__')
      end
    end

    value_conv = proc do |v|
      if v.kind_of?(String) and v =~ /\A(?:0|[1-9]\d*)\Z/
        v.to_i
      else
        v
      end
    end

    Dslh.deval(template, :key_conv => key_conv, :value_conv => value_conv, :exclude_key => exclude_key)
  end

  def define_template_func(scope)
    scope.instance_eval(<<-'EOS')
      def _join(data, options = {})
        options = {
          :undent    => true,
          :trim_mode => nil,
        }.merge(options)

        data = data.undent if options[:undent]

        @__refs__ = []
        def Ref(value); @__refs__ << {'Ref' => value}; "\0"; end
        data = ERB.new(data, nil, options[:trim_mode]).result(binding)
        undef Ref

        data = data.split("\0").zip(@__refs__)
        @__refs__ = nil

        data = data.flatten.select {|i| not i.nil? }.map {|i|
          if i.kind_of?(String)
            StringIO.new(i).to_a
          else
            i
          end
        }.flatten

        return {
          'Fn::Join' => ['', data]
        }
      end

      def _path(path, value = nil, &block)
        if block
          value = Dslh::ScopeBlock.nest(binding, 'block')
        end

        @__hash__[path] = value
      end
{'fraction_non_alphanumeric': 0.1307581573896353, 'fraction_numerical': 0.0011996161228406909, 'mean_word_length': 2.261737089201878, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 25, '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': '2188744', 'n_tokens_mistral': 2922, 'n_tokens_neox': 2829, 'n_words': 592}