HERE'S HOW YOU CAN USE SWITCH CASES IN LUA IMG iillustration-9.png Kidding! You can't! Lua doesn't have a `switch' operator. Instead, it has tables. And tables are actually much more interesting, and far easier to work into a routine that requires evaluating statements based on conditions. Don't believe me? Here's an example of how I've put tables to use. The context: I'm building a RSS reader for KOReader. Sometimes the RSS reader needs to fetch a web page, which it then parses, deconstructs, and re-builds as an EPUB. To re-build the web page into an EPUB, I create objects for each of the website's components, like the HTML document and any images it contains. I call these "items". Different types of items have different private methods, but they all share the same two data points: `path' and `content'. Because all items share these two data points, I've decided to make a common interface for their construction: `ItemFactory'. Supplying the `makeItem' method within `ItemFactory' with the item's `path' and `content' will "automatically" construct the item with the appropriate constructor. How? First: a file extension is derived from the item's `path.' This value is matched against the `ITEM_TYPES' table. The keys of this table represent the supported item types. The values for each key represent the item type's supported file formats (given as extensions). When a match is found, the table key is stored in a variable. Next, (and this is the exciting part) that variable's value is used as an index into the `ITEM_CONSTRUCTORS' table, which contains constructors for each supported item type. The indexed constructor is returned and then supplied with the `path' and `content' data that was passed to the factory. Cool, right? What I love so much about this no-switch switch-like logic is that the `makeItem' method basically reads like a unit test. It stays focused on returning errors when conditions aren't met. The actually divining of what code gets evaluated, and what that code does/looks like gets tucked away into a table. Extending the code is simple, maintaining the code is clear. It's bliss! ,---- | local ItemFactory = { | | } | | ItemFactory.ITEM_TYPES = { | xhtml = XHtmlItem.SUPPORTED_FORMATS, | image = Image.SUPPORTED_FORMATS | } | | ItemFactory.ITEM_CONSTRUCTORS = { | xhtml = function(path, content) | return XHtmlItem:new{ | path = path, | content = content, | } | end, | image = function(path, content) | return Image:new{ | path = path, | content = content | } | end | } | | function ItemFactory:makeItem(path, content) | local suffix = util.getFileNameSuffix( | string.lower(path) | ) | | local matched_type = ItemFactory:getItemTypeFromFileNameSuffix(suffix) | if not matched_type | then | return false, EpubError.ITEMFACTORY_UNSUPPORTED_TYPE | end | | local item_constructor = ItemFactory.ITEM_CONSTRUCTORS[matched_type] | if not item_constructor | then | return false, EpubError.ITEMFACTORY_NONEXISTENT_CONSTRUCTOR | end | | return item_constructor(path, content) | end | | function ItemFactory:getItemTypeFromFileNameSuffix(suffix) | local matched_item_type = nil | for item_type, supported_formats in pairs(ItemFactory.ITEM_TYPES) do | if supported_formats[suffix] | then | matched_item_type = item_type | break | end | end | return matched_item_type | end | | return ItemFactory `----