zenlish 0.1.25 → 0.2.00

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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