Happy Medium Between Generic Getters / Setters And Property Methods

<cfcomponent
	output="false"
	hint="Provides generic getter and setter methods based on intance properties and spoof methods.">
 
	<!--- Set up data structures and default data values. --->
 
	<!---
		Set up the list of properties that can be read and
		written using the generic getters and setters. For
		now, this will be just a generic list since we want
		this to be defined using the method list.
 
		We will maintain a separate list for the getter and
		setter properties.
	--->
	<cfset VARIABLES.PropertyList = {
		Get = "",
		Set = ""
		} />
 
 
	<cffunction
		name="Init"
		access="public"
		returntype="any"
		output="false"
		hint="Returns an intialized component.">
 
		<!--- Define the local scope. --->
		<cfset var LOCAL = {} />
 
		<!--- Get the Methods for this CFC. --->
		<cfset LOCAL.Methods = GetMetaData( THIS ).Functions />
 
 
		<!---
			Loop over the methods looking for the ones that are
			flagged with our spoof flag. These are the methods
			that should correspond to the property list.
		--->
		<cfloop
			index="LOCAL.Method"
			array="#LOCAL.Methods#">
 
			<!--- Check to see if this is a spoof. --->
			<cfif (
				StructKeyExists( LOCAL.Method, "kinky:type" ) AND
				(LOCAL.Method[ "kinky:type" ] EQ "spoof")
				)>
 
				<!--- Get the property method (get/set). --->
				<cfset LOCAL.PropertyMethod = Left(
					LOCAL.Method.Name,
					3
					) />
 
				<!--- Get the property name. --->
				<cfset LOCAL.PropertyName = Right(
					LOCAL.Method.Name,
					(Len( LOCAL.Method.Name ) - 3)
					) />
 
				<!---
					Check to see if this property is in the list
					of instance properties.
				--->
				<cfif StructKeyExists( VARIABLES.Instance, LOCAL.PropertyName )>
 
					<!---
						This value can be get/set using our
						generic getter and setter methods. Add
						the property to the valid property list
						and then delete the given method.
					--->
					<cfset VARIABLES.PropertyList[ LOCAL.PropertyMethod ] = ListAppend(
						VARIABLES.PropertyList[ LOCAL.PropertyMethod ],
						LOCAL.PropertyName
						) />
 
					<!--- Delete the spoof method. --->
					<cfset StructDelete( THIS, LOCAL.Method.Name ) />
 
				</cfif>
 
			</cfif>
 
		</cfloop>
 
		<!--- Return This reference. --->
		<cfreturn THIS />
	</cffunction>
 
 
	<cffunction
		name="Get"
		access="public"
		returntype="any"
		output="false"
		hint="Generic getter for valid instance properties.">
 
		<!--- Define arguments. --->
		<cfargument
			name="Property"
			type="string"
			required="true"
			hint="The property name being retreived."
			/>
 
 
		<!---
			Check to see if this property can be gotten based on
			access permissions.
		--->
		<cfif ListFindNoCase(
			VARIABLES.PropertyList.Get,
			ARGUMENTS.Property
			)>
 
			<!--- Return property. --->
			<cfreturn VARIABLES.Instance[ ARGUMENTS.Property ] />
 
		<cfelse>
 
			<!--- The property was invalid. --->
			<cfthrow
				type="Instance.InvalidProperty"
				message="Invalid property"
				detail="The property you requested, #UCase( ARGUMENTS.Property )#, is not a valid property for the generic getter."
				/>
 
		</cfif>
	</cffunction>
 
 
	<cffunction
		name="Set"
		access="public"
		returntype="any"
		output="false"
		hint="Generic setter for valid instance properties.">
 
		<!--- Define arguments. --->
		<cfargument
			name="Property"
			type="string"
			required="true"
			hint="The property name being set."
			/>
 
		<cfargument
			name="Value"
			type="any"
			required="true"
			hint="The property value being set."
			/>
 
 
		<!---
			Check to see if this property can be set based on
			access permissions.
		--->
		<cfif ListFindNoCase(
			VARIABLES.PropertyList.Set,
			ARGUMENTS.Property
			)>
 
			<!--- Set property. --->
			<cfset VARIABLES.Instance[ ARGUMENTS.Property ] = ARGUMENTS.Value />
 
			<!--- Return This reference for chaining. --->
			<cfreturn THIS />
 
		<cfelse>
 
			<!--- The property was invalid. --->
			<cfthrow
				type="Instance.InvalidProperty"
				message="Invalid property"
				detail="The property you set, #UCase( ARGUMENTS.Property )#, is not a valid property for the generic setter."
				/>
 
		</cfif>
	</cffunction>
 
 
	<cffunction
		name="OnMissingMethod"
		access="public"
		returntype="any"
		output="false"
		hint="Used to proxy the generic getter and setter methods.">
 
		<!--- Define arguments. --->
		<cfargument
			name="MissingMethodName"
			type="string"
			required="true"
			hint="The name of the requested method."
			/>
 
		<cfargument
			name="MissingMethodArguments"
			type="struct"
			required="true"
			hint="The struct of arguments."
			/>
 
 
		<!--- Define the local scope. --->
		<cfset var LOCAL = {} />
 
		<!--- Get the property method (get/set). --->
		<cfset LOCAL.PropertyMethod = Left(
			ARGUMENTS.MissingMethodName,
			3
			) />
 
		<!--- Get the property name. --->
		<cfset LOCAL.PropertyName = Right(
			ARGUMENTS.MissingMethodName,
			(Len( ARGUMENTS.MissingMethodName ) - 3)
			) />
 
 
		<!--- Check to see what the method is. --->
		<cfif (LOCAL.PropertyMethod EQ "Get")>
 
			<!--- Return property. --->
			<cfreturn THIS.Get( LOCAL.PropertyName ) />
 
		<cfelseif (LOCAL.PropertyMethod EQ "Set")>
 
			<!--- Set property. --->
			<cfreturn THIS.Set(
				LOCAL.PropertyName,
				ARGUMENTS.MissingMethodArguments[ 1 ]
				) />
 
		<cfelse>
 
			<!---
				If we have made it this far, then we are
				accessing an invalid method.
			--->
			<cfthrow
				type="Component.MissingMethod"
				message="Method does not exist"
				detail="The method you are attempting to access, #UCase( ARGUMENTS.MissingMethodName )#, is not a valid method of this component."
				/>
 
		</cfif>
	</cffunction>
 
</cfcomponent>

For Cut-and-Paste