<commit_before>require "active_support"
require "active_record"

require "view_model"

require "cerego_active_record_patches"
require "lazily"
require "concurrent"

class ActiveRecordViewModel < ViewModel
  # Defined before requiring components so components can refer to them at parse time
  NEW_ATTRIBUTE       = "_new"

  # for functional updates
  FUNCTIONAL_UPDATE_TYPE = "_update"
  ACTIONS_ATTRIBUTE      = "actions"
  VALUES_ATTRIBUTE       = "values"
  BEFORE_ATTRIBUTE       = "before"
  AFTER_ATTRIBUTE        = "after"

  require 'active_record_view_model/collections'
  require 'active_record_view_model/association_data'
  require 'active_record_view_model/update_data'
  require 'active_record_view_model/update_context'
  require 'active_record_view_model/update_operation'

  # An AR ViewModel wraps a single AR model
  attribute :model

  @@viewmodel_classes_by_name  = Concurrent::Map.new
  @@deferred_viewmodel_classes = Concurrent::Array.new

  class << self
    attr_reader :_members, :_associations, :_list_attribute_name
    attr_accessor :abstract_class, :synthetic, :unregistered

    delegate :transaction, to: :model_class

    def for_view_name(name)
      raise ViewModel::DeserializationError.new("ViewModel name cannot be nil") if name.nil?

      # Resolve names for any deferred viewmodel classes
      until @@deferred_viewmodel_classes.empty? do
        vm = @@deferred_viewmodel_classes.pop
        @@viewmodel_classes_by_name[vm.view_name] = vm unless vm.abstract_class || vm.synthetic || vm.unregistered
      end

      viewmodel_class = @@viewmodel_classes_by_name[name]

      if viewmodel_class.nil? || !(viewmodel_class < ActiveRecordViewModel)
        raise ViewModel::DeserializationError.new("ViewModel class for view name '#{name}' not found")
      end

      viewmodel_class
    end

    def inherited(subclass)
      # copy ViewModel setup
      subclass._attributes = self._attributes

      subclass.initialize_members

      # Store the subclass for later view name resolution
      @@deferred_viewmodel_classes << subclass
    end

    def initialize_members
      @_members = {}
      @_associations = {}
      @abstract_class = false
      @unregistered = false

      @generated_accessor_module = Module.new
      include @generated_accessor_module
    end

    # Specifies an attribute from the model to be serialized in this view
    def attribute(attr, read_only: false)
      _members[attr.to_s] = :attribute

      @generated_accessor_module.module_eval do
        define_method attr do
          model.public_send(attr)
        end

        define_method "serialize_#{attr}" do |json, serialize_context: self.class.new_serialize_context|
          value = self.public_send(attr)
          json.set! attr do
            self.class.serialize(value, json, serialize_context: serialize_context)
          end
        end

        if read_only
          define_method "deserialize_#{attr}" do |value, deserialize_context: self.class.new_deserialize_context|
            if value != self.public_send(attr)
              raise ViewModel::DeserializationError.new("Cannot edit read only attribute: #{attr}")
            end
          end
        else
          define_method "deserialize_#{attr}" do |value, deserialize_context: self.class.new_deserialize_context|
            model.public_send("#{attr}=", value)
          end
        end
      end
    end

    # Specifies that an attribute refers to an `acts_as_enum` constant.  This
    # provides special serialization behaviour to ensure that the constant's
    # string value is serialized rather than the model object.
    def acts_as_enum(*attrs)
      attrs.each do |attr|
        @generated_accessor_module.module_eval do
          redefine_method("serialize_#{attr}") do |json, serialize_context: self.class.new_serialize_context|<commit_msg>Add viewmodel reference when failing read only attr<commit_after>require "active_support"
require "active_record"

require "view_model"

require "cerego_active_record_patches"
require "lazily"
require "concurrent"

class ActiveRecordViewModel < ViewModel
  # Defined before requiring components so components can refer to them at parse time
  NEW_ATTRIBUTE       = "_new"

  # for functional updates
  FUNCTIONAL_UPDATE_TYPE = "_update"
  ACTIONS_ATTRIBUTE      = "actions"
  VALUES_ATTRIBUTE       = "values"
  BEFORE_ATTRIBUTE       = "before"
  AFTER_ATTRIBUTE        = "after"

  require 'active_record_view_model/collections'
  require 'active_record_view_model/association_data'
  require 'active_record_view_model/update_data'
  require 'active_record_view_model/update_context'
  require 'active_record_view_model/update_operation'

  # An AR ViewModel wraps a single AR model
  attribute :model

  @@viewmodel_classes_by_name  = Concurrent::Map.new
  @@deferred_viewmodel_classes = Concurrent::Array.new

  class << self
    attr_reader :_members, :_associations, :_list_attribute_name
    attr_accessor :abstract_class, :synthetic, :unregistered

    delegate :transaction, to: :model_class

    def for_view_name(name)
      raise ViewModel::DeserializationError.new("ViewModel name cannot be nil") if name.nil?

      # Resolve names for any deferred viewmodel classes
      until @@deferred_viewmodel_classes.empty? do
        vm = @@deferred_viewmodel_classes.pop
        @@viewmodel_classes_by_name[vm.view_name] = vm unless vm.abstract_class || vm.synthetic || vm.unregistered
      end

      viewmodel_class = @@viewmodel_classes_by_name[name]

      if viewmodel_class.nil? || !(viewmodel_class < ActiveRecordViewModel)
        raise ViewModel::DeserializationError.new("ViewModel class for view name '#{name}' not found")
      end

      viewmodel_class
    end

    def inherited(subclass)
      # copy ViewModel setup
      subclass._attributes = self._attributes

      subclass.initialize_members

      # Store the subclass for later view name resolution
      @@deferred_viewmodel_classes << subclass
    end

    def initialize_members
      @_members = {}
      @_associations = {}
      @abstract_class = false
      @unregistered = false

      @generated_accessor_module = Module.new
      include @generated_accessor_module
    end

    # Specifies an attribute from the model to be serialized in this view
    def attribute(attr, read_only: false)
      _members[attr.to_s] = :attribute

      @generated_accessor_module.module_eval do
        define_method attr do
          model.public_send(attr)
        end

        define_method "serialize_#{attr}" do |json, serialize_context: self.class.new_serialize_context|
          value = self.public_send(attr)
          json.set! attr do
            self.class.serialize(value, json, serialize_context: serialize_context)
          end
        end

        if read_only
          define_method "deserialize_#{attr}" do |value, deserialize_context: self.class.new_deserialize_context|
            if value != self.public_send(attr)
              raise ViewModel::DeserializationError.new("Cannot edit read only attribute: #{attr}", ViewModel::Reference.from_viewmodel(self))
            end
          end
        else
          define_method "deserialize_#{attr}" do |value, deserialize_context: self.class.new_deserialize_context|
            model.public_send("#{attr}=", value)
          end
        end
      end
    end

    # Specifies that an attribute refers to an `acts_as_enum` constant.  This
    # provides special serialization behaviour to ensure that the constant's
    # string value is serialized rather than the model object.
    def acts_as_enum(*attrs)
      attrs.each do |attr|
        @generated_accessor_module.module_eval do
          redefine_method("serialize_#{attr}") do |json, serialize_context: self.class.new_serialize_context|
{'fraction_non_alphanumeric': 0.07332393282912447, 'fraction_numerical': 0.0, 'mean_word_length': 3.358659217877095, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '903979', 'n_tokens_mistral': 2233, 'n_tokens_neox': 2186, 'n_words': 559}