zenlish 0.1.25 → 0.2.00

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -1
  3. data/LICENSE.txt +1 -1
  4. data/README.md +3 -3
  5. data/lib/zenlish/feature/boolean_domain.rb +29 -0
  6. data/lib/zenlish/feature/boolean_value.rb +9 -0
  7. data/lib/zenlish/feature/enumeration_domain.rb +32 -0
  8. data/lib/zenlish/feature/feature.rb +30 -0
  9. data/lib/zenlish/feature/feature_def.rb +48 -0
  10. data/lib/zenlish/feature/feature_domain.rb +9 -0
  11. data/lib/zenlish/feature/feature_struct.rb +24 -0
  12. data/lib/zenlish/feature/feature_struct_def.rb +44 -0
  13. data/lib/zenlish/feature/feature_struct_def_bearer.rb +65 -0
  14. data/lib/zenlish/feature/feature_value.rb +17 -0
  15. data/lib/zenlish/feature/identifier_domain.rb +29 -0
  16. data/lib/zenlish/feature/identifier_value.rb +9 -0
  17. data/lib/zenlish/feature/symbol_value.rb +8 -0
  18. data/lib/zenlish/inflect/atomic_o_expression.rb +9 -0
  19. data/lib/zenlish/inflect/composite_o_expression.rb +14 -0
  20. data/lib/zenlish/inflect/concatenation.rb +36 -0
  21. data/lib/zenlish/inflect/equals_literal.rb +25 -0
  22. data/lib/zenlish/inflect/feature_heading.rb +16 -0
  23. data/lib/zenlish/inflect/formal_argument.rb +11 -0
  24. data/lib/zenlish/inflect/heading.rb +11 -0
  25. data/lib/zenlish/inflect/inflection_rule.rb +28 -0
  26. data/lib/zenlish/inflect/inflection_table.rb +46 -0
  27. data/lib/zenlish/inflect/inflection_table_builder.rb +120 -0
  28. data/lib/zenlish/inflect/input_asis.rb +22 -0
  29. data/lib/zenlish/inflect/input_expression.rb +9 -0
  30. data/lib/zenlish/inflect/literal_asis.rb +17 -0
  31. data/lib/zenlish/inflect/matches_pattern.rb +26 -0
  32. data/lib/zenlish/inflect/method_heading.rb +16 -0
  33. data/lib/zenlish/inflect/nullary_input_expression.rb +8 -0
  34. data/lib/zenlish/inflect/output_expression.rb +6 -0
  35. data/lib/zenlish/inflect/substitution.rb +65 -0
  36. data/lib/zenlish/inflect/unary_input_expression.rb +13 -0
  37. data/lib/zenlish/inflect/unconditionally_true.rb +11 -0
  38. data/lib/zenlish/lang/dictionary.rb +19 -6
  39. data/lib/zenlish/lang/zenlish_grammar.rb +1 -0
  40. data/lib/zenlish/lex/empty_lexicon_factory.rb +3 -0
  41. data/lib/zenlish/lex/lexeme.rb +27 -4
  42. data/lib/zenlish/lex/lexicon.rb +3 -0
  43. data/lib/zenlish/lex/literal.rb +5 -1
  44. data/lib/zenlish/version.rb +1 -1
  45. data/lib/zenlish/wclasses/common_noun.rb +45 -0
  46. data/lib/zenlish/wclasses/noun.rb +21 -0
  47. data/lib/zenlish/wclasses/preposition.rb +5 -0
  48. data/lib/zenlish/wclasses/proper_noun.rb +11 -0
  49. data/lib/zenlish/wclasses/verb.rb +9 -1
  50. data/lib/zenlish/wclasses/word_class.rb +21 -6
  51. data/spec/spec_helper.rb +2 -3
  52. data/spec/zenlish/feature/boolean_domain_spec.rb +35 -0
  53. data/spec/zenlish/feature/boolean_value_spec.rb +26 -0
  54. data/spec/zenlish/feature/enumeration_domain_spec.rb +42 -0
  55. data/spec/zenlish/feature/feature_def_spec.rb +50 -0
  56. data/spec/zenlish/feature/feature_spec.rb +51 -0
  57. data/spec/zenlish/feature/feature_struct_def_bearer_spec.rb +54 -0
  58. data/spec/zenlish/feature/feature_struct_def_spec.rb +69 -0
  59. data/spec/zenlish/feature/identifier_domain_spec.rb +36 -0
  60. data/spec/zenlish/feature/identifier_value_spec.rb +26 -0
  61. data/spec/zenlish/feature/symbol_value_spec.rb +27 -0
  62. data/spec/zenlish/inflect/concatenation_spec.rb +40 -0
  63. data/spec/zenlish/inflect/equals_literal_spec.rb +58 -0
  64. data/spec/zenlish/inflect/feature_heading_spec.rb +30 -0
  65. data/spec/zenlish/inflect/formal_argument_spec.rb +25 -0
  66. data/spec/zenlish/inflect/inflection_rule_spec.rb +102 -0
  67. data/spec/zenlish/inflect/inflection_table_builder_spec.rb +127 -0
  68. data/spec/zenlish/inflect/inflection_table_spec.rb +129 -0
  69. data/spec/zenlish/inflect/input_asis_spec.rb +50 -0
  70. data/spec/zenlish/inflect/literal_asis_spec.rb +31 -0
  71. data/spec/zenlish/inflect/matches_pattern_spec.rb +61 -0
  72. data/spec/zenlish/inflect/method_heading_spec.rb +31 -0
  73. data/spec/zenlish/inflect/substitution_spec.rb +43 -0
  74. data/spec/zenlish/inflect/unconditionally_true_spec.rb +28 -0
  75. data/spec/zenlish/lang/dictionary_spec.rb +33 -0
  76. data/spec/zenlish/lex/lexeme_spec.rb +24 -9
  77. data/spec/zenlish/lex/literal_spec.rb +3 -11
  78. data/spec/zenlish/parser/lesson3_spec.rb +44 -0
  79. data/spec/zenlish/support/minimal_lexicon.rb +0 -2
  80. data/spec/zenlish/support/var2word.rb +5 -1
  81. data/spec/zenlish/wclasses/common_noun_spec.rb +25 -4
  82. data/spec/zenlish/wclasses/noun_spec.rb +31 -0
  83. data/spec/zenlish/wclasses/preposition_spec.rb +24 -0
  84. data/spec/zenlish/wclasses/verb_spec.rb +24 -0
  85. metadata +89 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2f0746a4aeb453208667a3e6eed3f97ffda61a31bb9b551f3f80a09e04881bd
4
- data.tar.gz: 958188827568032a3a71cc8021c3b6bdbaab6ddcd56508c2e13b93773b073631
3
+ metadata.gz: 68fb4d0914b284ffab37ba5f91c325918bcfaa4948adea0a747297e325c93fe6
4
+ data.tar.gz: e83dd3b97f088defef045fb01d5d6a7be202f02d4c45e85cdce3f2f718cf9ef2
5
5
  SHA512:
6
- metadata.gz: 738bbeefbef76458d197b0dc5e7de3d9f0994304500933532da3a7935070a1981d8456e32e945c0d4f6e7e51f2f55389e9eb6debf7f945a2b441531a829e4963
7
- data.tar.gz: 83237e8124d9d57ecd8d572b69ed88d26970c348ca2c2cef8b52a02a11a19d813eb867c1c44b56e9014a2e8f3bc5218e1ddf422cc08e42287f0b053bfdf9af7d
6
+ metadata.gz: 3de436eaced4062aade3ca3dc2d94915c284c2b38a5775ba3d6880d676cc8d0e3773a244eb1086ddca93f71c265f494b548fb114e7c30ea3b52ad1dbb8694a19
7
+ data.tar.gz: 7f55f80aad57993fcd1cadf75721f5f53fbd91fa8de6f620fb39fecd70892373dc69fe66fc3d13f43b272096aaf1c5afed60453ac126fb7c03fe9f0a1e435beb
data/CHANGELOG.md CHANGED
@@ -1,10 +1,26 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## [0.2.00] - 2020-01-30
4
+ A lot of internal additions, such an initial feature model, embryonic inflection model.
5
+ This is WIP.
6
+
7
+ ### Added
8
+ - New subfolder `feature` that hosts classes for implementing features (= properties that can be attached to words)
9
+ - New subfolder `inflect` that hosts classes for implmenting inflection tables (kind of decision tables)
10
+ ### Changed
11
+ - File `dictionary.rb`: new entries in lexicon `damage`, `difficult`
12
+ - File `dictionary.rb`: common nouns with special inflection rules (e.g. pluralized form) have their paradigm specified
13
+ - Class `Lexeme` can have its own set of feature definitions.
14
+ - Class `WordClass` ca have its own set of feature definitions.
15
+ - Class `Noun` has the feature definitions for: `NUMBER`, `COUNTABILITY` and `PARADIGM`
16
+
17
+
18
+
3
19
  ## [0.1.25] - 2019-12-06
4
20
  __Zenlish__ can parse all sentences in lesson 1, 2 and 3-A .. 3-G (352 sentences in total) from
5
21
  [Learn These Words First](http://learnthesewordsfirst.com/).
6
22
 
7
- ### Changed
23
+ ### Changed
8
24
  - File `lesson3_spec.rb`: tests include all sentences from lesson 3-A to 3-G.
9
25
  - `ZenlishGrammar`: refactoring of the predicative_sentence rules.
10
26
  - File `dictionary.rb`: new entries in lexicon `between`, `choose`, `machine`.
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2019, Dimitri Geshef
3
+ Copyright (c) 2019-2020, Dimitri Geshef
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -33,14 +33,14 @@ Over time, the zenlish gem will contain:
33
33
  - A lexicon [STARTED]
34
34
  - A context-free grammar [STARTED]
35
35
  - A parser [STARTED]
36
- - Feature unification (for number, gender agreement,...)[TODO]
36
+ - Feature unification (for number, gender agreement,...)[STARTED]
37
37
  - A simplified ontology[TODO]
38
38
 
39
39
 
40
- #### Some project metrics (v. 0.1.25)
40
+ #### Some project metrics (v. 0.2.00)
41
41
  |Metric|Value|
42
42
  |:-:|:-:|
43
- | Number of lemmas in dictionary | 138 |
43
+ | Number of lemmas in dictionary | 141 |
44
44
  | [Coverage 100 commonest English words](https://en.wikipedia.org/wiki/Most_common_words_in_English) | 61% |
45
45
  | Number of production rules in grammar | 185 |
46
46
  | Number of lessons covered | 23 |
@@ -0,0 +1,29 @@
1
+ require 'singleton'
2
+ require_relative 'feature_domain'
3
+ require_relative 'boolean_value'
4
+
5
+ module Zenlish
6
+ module Feature
7
+ class BooleanDomain < FeatureDomain
8
+ include Singleton # Use the Singleton design patttern
9
+
10
+ def build_value(aValue)
11
+ BooleanValue.new(validated_value(aValue))
12
+ end
13
+
14
+ def include?(aValue)
15
+ aValue.kind_of?(TrueClass) || aValue.kind_of?(FalseClass)
16
+ end
17
+
18
+ private
19
+
20
+ def validated_value(aValue)
21
+ if not aValue.is_a?(FalseClass) and not aValue.is_a?(TrueClass)
22
+ raise StandardError, "Expected a boolean instead of #{aValue.class}."
23
+ end
24
+
25
+ aValue
26
+ end
27
+ end # class
28
+ end # module
29
+ end # module
@@ -0,0 +1,9 @@
1
+ require_relative 'feature_value'
2
+
3
+ module Zenlish
4
+ module Feature
5
+ class BooleanValue < FeatureValue
6
+
7
+ end # class
8
+ end # module
9
+ end # module
@@ -0,0 +1,32 @@
1
+ require_relative 'feature_domain'
2
+ require_relative 'symbol_value'
3
+
4
+ module Zenlish
5
+ module Feature
6
+ class EnumerationDomain < FeatureDomain
7
+ attr_reader :enum
8
+
9
+ def initialize(*symbols)
10
+ @enum = symbols
11
+ end
12
+
13
+ def build_value(aValue)
14
+ SymbolValue.new(validated_value(aValue))
15
+ end
16
+
17
+ def include?(aValue)
18
+ enum.include?(aValue)
19
+ end
20
+
21
+ private
22
+
23
+ def validated_value(aValue)
24
+ unless include?(aValue)
25
+ raise StandardError, "#{aValue} isn't part of enumeration [#{enum.join(', ')}]."
26
+ end
27
+
28
+ aValue
29
+ end
30
+ end # class
31
+ end # module
32
+ end # module
@@ -0,0 +1,30 @@
1
+ require 'forwardable'
2
+
3
+ module Zenlish
4
+ module Feature
5
+ class Feature
6
+ # Forwardable mix-in module to implement delegation of specified methods.
7
+ extend Forwardable
8
+
9
+ # The feature definition
10
+ attr_reader :definition
11
+
12
+ attr_reader :binding
13
+
14
+ def_delegators :@definition, :name, :domain
15
+
16
+ # @param aDefinition [FeatureDef]
17
+ def initialize(aDefinition)
18
+ @definition = aDefinition
19
+ end
20
+
21
+ def bound?
22
+ not binding.nil?
23
+ end
24
+
25
+ def bind_to(aFeatureValue)
26
+ @binding = aFeatureValue
27
+ end
28
+ end # class
29
+ end # module
30
+ end # module
@@ -0,0 +1,48 @@
1
+ require_relative 'enumeration_domain'
2
+ require_relative 'feature_value'
3
+
4
+ module Zenlish
5
+ module Feature
6
+ class FeatureDef
7
+ # @return [String] the name of the feature
8
+ attr_reader :name
9
+
10
+ # @return [FeatureDomain] the set of potential values the feature can take
11
+ attr_reader :domain
12
+
13
+ # @return [FeatureValue] the default value for the feature.
14
+ attr_reader :default
15
+
16
+ # @param aName [String] the name of the feature
17
+ # @param aDomain [FeatureDomain]
18
+ # @param aDefault [FeatureValue, NilClass]
19
+ def initialize(aName, aDomain, aDefault = nil)
20
+ @name = validated_name(aName)
21
+ @domain = aDomain
22
+ @default = validated_default(domain, aDefault)
23
+ end
24
+
25
+ private
26
+
27
+ def validated_name(aName)
28
+ raise StandardError, 'feature name cannot be empty.' if aName.empty?
29
+ aName.dup
30
+ end
31
+
32
+ def validated_default(aDomain, aDefault)
33
+ if aDefault
34
+ default = aDefault
35
+ elsif aDomain.is_a?(BooleanDomain)
36
+ default = nil
37
+ else aDomain.is_a?(EnumerationDomain)
38
+ if aDomain.enum.size == 1
39
+ val = FeatureValue.new(aDomain.enum[0])
40
+ default = val
41
+ else
42
+ default = nil
43
+ end
44
+ end
45
+ end
46
+ end # class
47
+ end # module
48
+ end # module
@@ -0,0 +1,9 @@
1
+ module Zenlish
2
+ module Feature
3
+ class FeatureDomain
4
+ def include?(aValue)
5
+ raise NotImplementedError, 'Implemented this method in subclass(es).'
6
+ end
7
+ end # class
8
+ end # module
9
+ end # module
@@ -0,0 +1,24 @@
1
+ require_relative 'feature_value'
2
+ require_relative 'feature'
3
+
4
+ module Zenlish
5
+ module Feature
6
+ class FeatureStruct < FeatureValue
7
+ def initialize(aStructDef)
8
+ featrs = build_features(aStructDef)
9
+ super(aStructDef, featrs)
10
+ end
11
+
12
+ private
13
+
14
+ def build_features(aStructDef)
15
+ feats = []
16
+ aStructDef.struct.each_value do |feature_def|
17
+ feats << Feature.new(feature_def)
18
+ end
19
+
20
+ feats
21
+ end
22
+ end # class
23
+ end # module
24
+ end # module
@@ -0,0 +1,44 @@
1
+ require_relative 'feature_domain'
2
+
3
+ module Zenlish
4
+ module Feature
5
+ class FeatureStructDef < FeatureDomain
6
+ attr_reader :parent
7
+ attr_reader :struct
8
+
9
+ # @param aParent [FeatureStructDef]
10
+ def initialize(aParent = nil)
11
+ @parent = validated_parent(aParent)
12
+ @struct = {}
13
+ end
14
+
15
+ # @param aFeatureName [String]
16
+ def [](aFeatureName)
17
+ return struct[aFeatureName] if struct.include? aFeatureName
18
+ if parent
19
+ p_struct = parent.struct
20
+ return p_struct[aFeatureName] if p_struct.include? aFeatureName
21
+ end
22
+
23
+ raise StandardError, "Unknown feature name #{aFeatureName}"
24
+ end
25
+
26
+ # @param aFeatureDef [Zenlish::Feature::FeatureDef]
27
+ def add_feature_def(aFeatureDef)
28
+ struct[aFeatureDef.name] = aFeatureDef
29
+ end
30
+
31
+ private
32
+
33
+ def validated_parent(aParent)
34
+ if aParent.kind_of?(FeatureStructDef)
35
+ aParent
36
+ elsif aParent
37
+ aParent.struct
38
+ else
39
+ nil
40
+ end
41
+ end
42
+ end # class
43
+ end # module
44
+ end # module
@@ -0,0 +1,65 @@
1
+ require_relative 'boolean_domain'
2
+ require_relative 'identifier_domain'
3
+ require_relative 'enumeration_domain'
4
+ require_relative 'feature_def'
5
+ require_relative 'feature_value'
6
+ require_relative 'feature_struct_def'
7
+
8
+ module Zenlish
9
+ module Feature
10
+ # Mix-in module. It adds a feature structure defintion to its host and
11
+ # also factory methods to ease feature definition manipulation.
12
+ module FeatureStructDefBearer
13
+ # @param aParentStruct [Feature::FeatureStructDef] parent structure
14
+ # @param aFeatureHash [Hash] hash with pairs of the form: String => FeatureDomain
15
+ def init_struct_def(aParentStruct, aFeatureHash)
16
+ @struct = FeatureStructDef.new(aParentStruct)
17
+ aFeatureHash.each_pair do |name, domain|
18
+ feature_def(name => domain)
19
+ end
20
+ end
21
+
22
+ # @return [Feature::FeatureStructDef]
23
+ def struct
24
+ @struct
25
+ end
26
+
27
+ # Retrieve feature definition with given name.
28
+ # @param aName [String] Name of feature def to search for.
29
+ # @return [Feature::FeatureDef, NilClass]
30
+ def [](aName)
31
+ struct[aName]
32
+ end
33
+
34
+ # @return [Feature::BooleanDomain]
35
+ def boolean
36
+ BooleanDomain.instance
37
+ end
38
+
39
+ # @return [Feature::EnumerationDomain]
40
+ def enumeration(*items)
41
+ EnumerationDomain.new(*items)
42
+ end
43
+
44
+ def identifier(aDefaultValue = nil)
45
+ IdentifierDomain.instance
46
+ end
47
+
48
+ # @param aPair [Hash] hash with one pair { String => FeatureDomain }
49
+ def feature_def(aPair)
50
+ if aPair.values[0].is_a?(Array)
51
+ dom, val = aPair.values[0]
52
+ val = dom.build_value(val) unless val.kind_of?(FeatureValue)
53
+ featr_def = FeatureDef.new(aPair.keys[0], dom, val)
54
+ else
55
+ featr_def = FeatureDef.new(aPair.keys[0], aPair.values[0])
56
+ end
57
+ @struct.add_feature_def(featr_def)
58
+ end
59
+
60
+ def feature_def_dsl(&aBlock)
61
+ instance_eval(&aBlock)
62
+ end
63
+ end # module
64
+ end # module
65
+ end # module
@@ -0,0 +1,17 @@
1
+ module Zenlish
2
+ module Feature
3
+ class FeatureValue
4
+ attr_reader :val
5
+
6
+ def initialize(aValue)
7
+ @val = aValue
8
+ end
9
+
10
+ protected
11
+
12
+ def valid_value()
13
+ raise NotImplementedError
14
+ end
15
+ end # class
16
+ end # module
17
+ end # module
@@ -0,0 +1,29 @@
1
+ require 'singleton'
2
+ require_relative 'feature_domain'
3
+ require_relative 'identifier_value'
4
+
5
+ module Zenlish
6
+ module Feature
7
+ class IdentifierDomain < FeatureDomain
8
+ include Singleton # Use the ingletion design pattern
9
+
10
+ def build_value(aValue)
11
+ IdentifierValue.new(validated_value(aValue))
12
+ end
13
+
14
+ def include?(aValue)
15
+ aValue =~ /^[a-zA-Z\_][a-zA-Z0-9\_]*$/
16
+ end
17
+
18
+ private
19
+
20
+ def validated_value(aValue)
21
+ unless include?(aValue)
22
+ raise StandardError, "#{aValue} isn't a valid identifier."
23
+ end
24
+
25
+ aValue
26
+ end
27
+ end # class
28
+ end # module
29
+ end # module
@@ -0,0 +1,9 @@
1
+ require_relative 'feature_value'
2
+
3
+ module Zenlish
4
+ module Feature
5
+ class IdentifierValue < FeatureValue
6
+
7
+ end # class
8
+ end # module
9
+ end # module
@@ -0,0 +1,8 @@
1
+ require_relative 'feature_value'
2
+
3
+ module Zenlish
4
+ module Feature
5
+ class SymbolValue < FeatureValue
6
+ end # class
7
+ end # module
8
+ end # module
@@ -0,0 +1,9 @@
1
+ require_relative 'output_expression'
2
+
3
+ module Zenlish
4
+ module Inflect
5
+ class AtomicOExpression < OutputExpression
6
+ end # class
7
+ end # module
8
+ end # module
9
+
@@ -0,0 +1,14 @@
1
+ require_relative 'output_expression'
2
+
3
+ module Zenlish
4
+ module Inflect
5
+ class CompositeOExpression < OutputExpression
6
+ attr_reader :children
7
+
8
+ def initialize(theChildren)
9
+ @children = theChildren.dup
10
+ end
11
+ end # class
12
+ end # module
13
+ end # module
14
+
@@ -0,0 +1,36 @@
1
+ require_relative 'literal_asis'
2
+ require_relative 'composite_o_expression'
3
+
4
+ module Zenlish
5
+ module Inflect
6
+ class Concatenation < CompositeOExpression
7
+
8
+ def initialize(argument1, argument2)
9
+ super([validated_argument(argument1), validated_argument(argument2)])
10
+ end
11
+
12
+ def generate(headings, lexeme, values)
13
+ part1 = children[0].generate(headings, lexeme, values)
14
+ part2 = children[-1].generate(headings, lexeme, values)
15
+
16
+ part1 + part2
17
+ end
18
+
19
+ private
20
+
21
+ def validated_argument(anArgument)
22
+ arg = nil
23
+ if anArgument.kind_of?(String)
24
+ arg = LiteralAsIs.new(anArgument)
25
+ elsif anArgument.kind_of?(OutputExpression)
26
+ arg = anArgument
27
+ else
28
+ err_msg = "Unexpected type of argument #{anArgument.inspect}."
29
+ raise StandardError, err_msg
30
+ end
31
+
32
+ arg
33
+ end
34
+ end # class
35
+ end # module
36
+ end # module
@@ -0,0 +1,25 @@
1
+ require_relative 'unary_input_expression'
2
+
3
+ module Zenlish
4
+ module Inflect
5
+ class EqualsLiteral < UnaryInputExpression
6
+ attr_reader :literal
7
+
8
+ def initialize(anArgument, aLiteral)
9
+ super(anArgument)
10
+ @literal = aLiteral
11
+ end
12
+
13
+ def success?(headings, lexeme, actuals)
14
+ if actuals.empty?
15
+ hd = headings[argument.index]
16
+ feat_def = hd.evaluate_for(lexeme)
17
+ feat_def.domain.include?(literal)
18
+ else
19
+ val = actuals[argument.index]
20
+ val == literal
21
+ end
22
+ end
23
+ end # class
24
+ end # module
25
+ end # module
@@ -0,0 +1,16 @@
1
+ require_relative 'heading'
2
+
3
+ module Zenlish
4
+ module Inflect
5
+ class FeatureHeading < Heading
6
+
7
+ def initialize(aLabel)
8
+ super(aLabel)
9
+ end
10
+
11
+ def evaluate_for(aFeatureBearer)
12
+ aFeatureBearer[label]
13
+ end
14
+ end # class
15
+ end # module
16
+ end # module
@@ -0,0 +1,11 @@
1
+ module Zenlish
2
+ module Inflect
3
+ class FormalArgument
4
+ attr_reader :index
5
+
6
+ def initialize(anIndex)
7
+ @index = anIndex
8
+ end
9
+ end # class
10
+ end # module
11
+ end # module
@@ -0,0 +1,11 @@
1
+ module Zenlish
2
+ module Inflect
3
+ class Heading
4
+ attr_reader :label
5
+
6
+ def initialize(aLabel)
7
+ @label = aLabel
8
+ end
9
+ end # class
10
+ end # module
11
+ end # module
@@ -0,0 +1,28 @@
1
+ module Zenlish
2
+ module Inflect
3
+ # An inflection rule has two-parts:
4
+ # - a set of input conditions
5
+ # - a consequent part which tells how to inflect a lexeme
6
+ class InflectionRule
7
+ attr_reader :conditions
8
+ attr_reader :consequent
9
+
10
+ def initialize(theConditions, aConsequentExpr)
11
+ @conditions = theConditions
12
+ @consequent = aConsequentExpr
13
+ end
14
+
15
+ def success?(theHeadings, aLexeme, actuals)
16
+ conditions.all? { |cond| cond.success?(theHeadings, aLexeme, actuals) }
17
+ end
18
+
19
+ def apply(theHeadings, aLexeme, actuals)
20
+ consequent.generate(theHeadings, aLexeme, actuals)
21
+ end
22
+
23
+ def force_apply(theHeadings, aLexeme)
24
+ consequent.generate(theHeadings, aLexeme)
25
+ end
26
+ end # class
27
+ end # module
28
+ end # module
@@ -0,0 +1,46 @@
1
+
2
+ module Zenlish
3
+ module Inflect
4
+ class InflectionTable
5
+ attr_reader :name
6
+ attr_reader :headings
7
+ attr_reader :rules
8
+
9
+ def initialize(aName)
10
+ @name = aName
11
+ @headings = []
12
+ @rules = []
13
+ end
14
+
15
+ def add_heading(aHeading)
16
+ @headings << aHeading
17
+ end
18
+
19
+ def add_rule(aRule)
20
+ @rules << aRule
21
+ end
22
+
23
+ def inflect(aLexeme, theConstraints)
24
+ err_msg = "Table has #{headings.size} headings."
25
+ raise StandardError, err_msg if theConstraints.size != headings.size
26
+ actuals = []
27
+ headings.each_with_index do |hd, idx|
28
+ if theConstraints[idx]
29
+ actuals << theConstraints[idx]
30
+ else
31
+ actuals << hd.evaluate_for(aLexeme)
32
+ end
33
+ end
34
+ # Hit policy: first
35
+ matching_rule = rules.find do |rule|
36
+ rule.success?(headings, aLexeme, actuals)
37
+ end
38
+ unless matching_rule
39
+ err_msg = "No rule in table covers case: lexeme #{aLexeme}, actuals: #{p actuals}."
40
+ raise StandardError, err_msg
41
+ end
42
+ matching_rule.apply(headings, aLexeme, actuals)
43
+ end
44
+ end # class
45
+ end # module
46
+ end # module