<commit_before>#encoding: utf-8
require 'set'
$depth = 0
class UIC::Asset
	class Root
		@properties = {}
		class << self
			attr_reader :name
			def properties
				(ancestors[1].respond_to?(:properties) ? ancestors[1].properties : {}).merge(@properties)
			end

			def each
				(@by_name.values - [self]).each{ |klass| yield klass }
			end
			include Enumerable

			def inspect
				"<#{@name}>"
			end
		end

		def properties
			self.class.properties
		end

		attr_accessor :presentation, :el
		def initialize( presentation, element )
			@presentation = presentation
			@el = element
		end

		def type
			self.class.name
			# self.class.name.split('::').last
		end

		def parent
			presentation.parent_asset(@el)
		end

		def children
			presentation.child_assets(@el)
		end

		# Find the owning component (even if you are a component)
		def component
			presentation.owning_component(@el)
		end

		def component?
			@el.name == 'Component'
		end

		def master?
			presentation.master?(@el)
		end

		def slide?
			false
		end

		def has_slide?(slide_name_or_index)
			presentation.has_slide?(@el,slide_name_or_index)
		end

		def slides
			presentation.slides_for(@el)
		end

		def on_slide(slide_name_or_index)
			if has_slide?(slide_name_or_index)
				UIC::SlideValues.new( self, slide_name_or_index )
			end
		end

		def path
			@path ||= @presentation.path_to(@el)
		end

		def name
			properties['name'].get( self, presentation.slide_index(@el) )
		end

		def name=( new_name )
			properties['name'].set( self, new_name, presentation.slide_index(@el) )
		end

		# Get the value(s) of an attribute
		def [](attribute_name, slide_name_or_index=nil)
			# puts "Looking for #{attribute_name.inspect} on slide #{slide_name_or_index.inspect} of #{@el.name}##{@el['id']}"
			if property = properties[attribute_name]
				if slide_name_or_index
					property.get( self, slide_name_or_index ) if has_slide?(slide_name_or_index)
				else
					UIC::ValuesPerSlide.new(@presentation,self,property)
				end
			end
		end

		# Set the value of an attribute, either across all slides, or on a particular slide
		# el['foo']   = 42
		# el['foo',0] = 42
		def []=( attribute_name, slide_name_or_index=nil, new_value )
			if property = properties[attribute_name] then
				property.set(self,new_value,slide_name_or_index)
			end
		end

		def to_xml
			@el.to_xml
		end
		def inspect
			"<asset #{@el.name}##{@el['id']}>"
		end

		def to_s
			"<#{type} #{path}>"
		end

		def ==(other)
			(self.class==other.class) && (el==other.el)
		end
		alias_method :eql?, :==
	end

	attr_reader :by_name

	HIER = {}
	%w[Asset Slide Scene].each{ |s| HIER[s] = 'Root' }
	%w[Node Behavior Effect Image Layer Material MaterialBase ReferencedMaterial RenderPlugin].each{ |s| HIER[s]='Asset' }
	%w[Camera Component Group Light Model Text].each{ |s| HIER[s]='Node' }

	def initialize(xml)
		@by_name = {'Root'=>Root}

		doc = Nokogiri.XML(xml)
		hack_in_slide_names!(doc)

		HIER.each do |class_name,parent_class_name|
			parent_class = @by_name[parent_class_name]
			el = doc.root.at(class_name)
			@by_name[class_name] = create_class(el,parent_class,el.name)
			UIC::Asset.const_set( el.name, @by_name[class_name] ) # give the class instance a name by pointing a constant to it :/
		end

		@by_name['State'] = @by_name['Slide']
		@by_name['Slide'].instance_eval do
			attr_accessor :index, :name
			define_method :inspect do
				"<slide ##{index} of #{@el['component'] || @el.parent['component']}>"
			end
			define_method(:slide?){ true }
		end
	end

	# Creates a class from MetaData.xml with accessors for the <Property> listed.
	# Instances of the class are associated with a presentation and know how to 
	# get/set values in that XML based on value types, slides, defaults.
	# Also used to create classes from effects, materials, and behavior preambles.
	def create_class(el,parent_class,name='CustomAsset')
		Class.new(parent_class) do
			@name = name
			@properties = Hash[ el.css("Property").map do |e|
				type = e['type'] || (e['list'] ? 'String' : 'Float')
				type = "Float" if type=="float"
				property = UIC::Property.const_get(type).new(e)
				[ property.name, UIC::Property.const_get(type).new(e) ]
			end ]
		end
	end

	def new_instance(presentation,el)
		@by_name[el.name].new(presentation,el)
	end

	def hack_in_slide_names!(doc)
		doc.at('Slide') << '<Property name="name" formalName="Name" type="String" default="Slide" hidden="True" />'
	end<commit_msg>Assets can use / operator to find children or descendants<commit_after>#encoding: utf-8
require 'set'
$depth = 0
class UIC::Asset
	class Root
		@properties = {}
		class << self
			attr_reader :name
			def properties
				(ancestors[1].respond_to?(:properties) ? ancestors[1].properties : {}).merge(@properties)
			end

			def each
				(@by_name.values - [self]).each{ |klass| yield klass }
			end
			include Enumerable

			def inspect
				"<#{@name}>"
			end
		end

		def properties
			self.class.properties
		end

		def at(sub_path)
			presentation.at(sub_path,@el)
		end
		alias_method :/, :at

		attr_accessor :presentation, :el
		def initialize( presentation, element )
			@presentation = presentation
			@el = element
		end

		def type
			self.class.name
			# self.class.name.split('::').last
		end

		def parent
			presentation.parent_asset(@el)
		end

		def children
			presentation.child_assets(@el)
		end

		# Find the owning component (even if you are a component)
		def component
			presentation.owning_component(@el)
		end

		def component?
			@el.name == 'Component'
		end

		def master?
			presentation.master?(@el)
		end

		def slide?
			false
		end

		def has_slide?(slide_name_or_index)
			presentation.has_slide?(@el,slide_name_or_index)
		end

		def slides
			presentation.slides_for(@el)
		end

		def on_slide(slide_name_or_index)
			if has_slide?(slide_name_or_index)
				UIC::SlideValues.new( self, slide_name_or_index )
			end
		end

		def path
			@path ||= @presentation.path_to(@el)
		end

		def name
			properties['name'].get( self, presentation.slide_index(@el) )
		end

		def name=( new_name )
			properties['name'].set( self, new_name, presentation.slide_index(@el) )
		end

		# Get the value(s) of an attribute
		def [](attribute_name, slide_name_or_index=nil)
			# puts "Looking for #{attribute_name.inspect} on slide #{slide_name_or_index.inspect} of #{@el.name}##{@el['id']}"
			if property = properties[attribute_name]
				if slide_name_or_index
					property.get( self, slide_name_or_index ) if has_slide?(slide_name_or_index)
				else
					UIC::ValuesPerSlide.new(@presentation,self,property)
				end
			end
		end

		# Set the value of an attribute, either across all slides, or on a particular slide
		# el['foo']   = 42
		# el['foo',0] = 42
		def []=( attribute_name, slide_name_or_index=nil, new_value )
			if property = properties[attribute_name] then
				property.set(self,new_value,slide_name_or_index)
			end
		end

		def to_xml
			@el.to_xml
		end
		def inspect
			"<asset #{@el.name}##{@el['id']}>"
		end

		def to_s
			"<#{type} #{path}>"
		end

		def ==(other)
			(self.class==other.class) && (el==other.el)
		end
		alias_method :eql?, :==
	end

	attr_reader :by_name

	HIER = {}
	%w[Asset Slide Scene].each{ |s| HIER[s] = 'Root' }
	%w[Node Behavior Effect Image Layer Material MaterialBase ReferencedMaterial RenderPlugin].each{ |s| HIER[s]='Asset' }
	%w[Camera Component Group Light Model Text].each{ |s| HIER[s]='Node' }

	def initialize(xml)
		@by_name = {'Root'=>Root}

		doc = Nokogiri.XML(xml)
		hack_in_slide_names!(doc)

		HIER.each do |class_name,parent_class_name|
			parent_class = @by_name[parent_class_name]
			el = doc.root.at(class_name)
			@by_name[class_name] = create_class(el,parent_class,el.name)
			UIC::Asset.const_set( el.name, @by_name[class_name] ) # give the class instance a name by pointing a constant to it :/
		end

		@by_name['State'] = @by_name['Slide']
		@by_name['Slide'].instance_eval do
			attr_accessor :index, :name
			define_method :inspect do
				"<slide ##{index} of #{@el['component'] || @el.parent['component']}>"
			end
			define_method(:slide?){ true }
		end
	end

	# Creates a class from MetaData.xml with accessors for the <Property> listed.
	# Instances of the class are associated with a presentation and know how to
	# get/set values in that XML based on value types, slides, defaults.
	# Also used to create classes from effects, materials, and behavior preambles.
	def create_class(el,parent_class,name='CustomAsset')
		Class.new(parent_class) do
			@name = name
			@properties = Hash[ el.css("Property").map do |e|
				type = e['type'] || (e['list'] ? 'String' : 'Float')
				type = "Float" if type=="float"
				property = UIC::Property.const_get(type).new(e)
				[ property.name, UIC::Property.const_get(type).new(e) ]
			end ]
		end
	end

	def new_instance(presentation,el)
		@by_name[el.name].new(presentation,el)
	end

	def hack_in_slide_names!(doc)
		doc.at('Slide') << '<Property name="name" formalName="Name" type="String" default="Slide" hidden="True" />'
	end
{'fraction_non_alphanumeric': 0.1309510598157807, 'fraction_numerical': 0.0019975585395627564, 'mean_word_length': 3.9489291598023066, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, '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': '6927514', 'n_tokens_mistral': 3668, 'n_tokens_neox': 3148, 'n_words': 773}