<commit_before>#/usr/bin/ruby -w

require_relative 'lib/striuct'

#* Macro "member" provides one of Struct+ interfaces for condtions and a procedure.
    class User < Striuct.new
      member :id, Integer
      member :address, /\A((\w+) ?)+\z/
      member :age, (20..140)
      member :name, /\A\w+\z/, /\A\w+ \w+\z/
    end

    # pass
    user = User.new 128381, 'Tokyo Japan', 20
    p user

    # pass
    user.age = 30
    user.name = '<NAME>'
    p user

    # fail (Exception  Striuct::ConditionError)
    begin
      user[:id] = 10.0
    rescue
      p $!
    end
    
    begin
      user[1] = 'Tokyo-to'
    rescue
      p $!
    end

    begin
      user.age = 19
    rescue
      p $!
    end

    begin
      user.name = nil
    rescue
      p $!
    end

#* more detail checker do you need, you can use functional object here.
#  and Proc(lambda) run self's context
    class Game < Striuct
      member :monsters, ->monsters{[monsters - characters].empty?}
      member :characters, Array
    end
 
#* but, link to object is able to clash
#  use easy checker this case
    user.strict? #=> true
    user.address.clear
    user.strict? #=> false

#* procedure for cast case
    class User2 < Striuct.new
      member :age, /\A\d+\z/, Numeric do |arg|
        Integer arg
      end
    end
    
    user2 = User2.new
    user2.age = 9 #=> 9(Fixnum)
    user2.age = 10.1 #=> 10(Fixnum)
    user2.age = '10' #=> 10(Fixnum)

#* use default value
    class User3 < Striuct.new
      member  :lank, Fixnum
      default :lank, 3
      member  :name
    end
    
    user3 = User3.new
    user3.lank #=> 3
    
# Standard Struct always define "nil is default". ...realy?
   user3.name  #=> nil
   user3.assign? :name #=> false
   user3.name = nil
   user3.assign? :name #=> true

#* and keeping Struct's good interface
    Sth1 = Striuct.new :id, :last_name, :family_name, :address, :age

    Sth2 = Striuct.new do
      def m
      end
    end<commit_msg>modify and added example<commit_after>#/usr/bin/ruby -w

require_relative 'lib/striuct'

def debug(message)
  puts "line: #{caller[0].slice(/:(\w+)/, 1)}"
  puts message.inspect, '-' * 80
end

#* Macro "member" provides one of Struct+ interfaces for condtions and a flavor.
class User < Striuct.new
  member :id, Integer
  member :address, /\A((\w+) ?)+\z/
  member :age, (20..140)
  member :name, /\A\w+\z/, /\A\w+ \w+\z/
end

# pass
user = User.new 128381, 'Tokyo Japan', 20
debug user

# pass
user.age = 30
user.name = '<NAME>'
debug user

# fail (Exception  Striuct::ConditionError)
begin
  user[:id] = 10.0
rescue
  debug $!
end

begin
  user[1] = 'Tokyo-to'
rescue
  debug $!
end

begin
  user.age = 19
rescue
  debug $!
end

begin
  user.name = nil
rescue
  debug $!
end

#* but, linked objects are able to clash
debug user
debug user.strict?
debug user
debug user.strict?

#* more detail checker do you need, you can use functional object.
module Game
  class Character
  end

  class DB < Striuct.new
    member :monsters, ->monsters{(monsters - characters).empty?}
    member :characters, ->characters{characters.all?{|c|c.kind_of? Character}}
  end
  
  monster = Character.new
  db = DB.new
  
  begin
    db.characters = [1, 2]
  rescue
    debug $!
  end
  
  db.characters = [monster, Character.new]
  debug db
  
  begin
    db.monsters = [:dummy]
  rescue
    debug $!
  end
  
  db.monsters = [monster]
  debug db
end

 
#* with flavor for type cast
class User2 < Striuct.new
  member :age, /\A\d+\z/, Numeric do |arg|
    Integer arg
  end
end

user2 = User2.new
user2.age = 9
debug user2

user2.age = 10.1
debug user2

user2.age = '10'
debug user2

#* use default value
class User3 < Striuct.new
  member  :lank, Fixnum
  default :lank, 3
  member  :name
end

user3 = User3.new
user3.lank #=> 3

# Standard Struct always define "nil is default". ...realy?
user3.name  #=> nil
user3.assign? :name #=> false
user3.name = nil
user3.assign? :name #=> true

#* and keeping Struct's good interface
Sth1 = Striuct.new :id, :last_name, :family_name, :address, :age

debug Sth1.new

Sth2 = Striuct.new do
  def my_special_method
  end
end

debug Sth2.new.respond_to?(:my_special_method)
{'fraction_non_alphanumeric': 0.1256607400288323, 'fraction_numerical': 0.025468524747717443, 'mean_word_length': 2.495382031905961, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 21, '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': '1108933', 'n_tokens_mistral': 1615, 'n_tokens_neox': 1526, 'n_words': 460}